From 1a2a1e2b1fd6a1a1a2cac3cfef0b88a21470d71d Mon Sep 17 00:00:00 2001 From: itojun Date: Mon, 31 Jan 2000 14:18:52 +0000 Subject: [PATCH] bring in latest KAME ipsec tree. - interop issues in ipcomp is fixed - padding type (after ESP) is configurable - key database memory management (need more fixes) - policy specification is revisited XXX m->m_pkthdr.rcvif is still overloaded - hope to fix it soon --- sys/conf/files | 3 +- sys/netinet/in_pcb.h | 6 +- sys/netinet/ip_input.c | 18 +- sys/netinet/ip_output.c | 27 +- sys/netinet/raw_ip.c | 4 +- sys/netinet/tcp_input.c | 23 +- sys/netinet/tcp_subr.c | 8 +- sys/netinet/tcp_usrreq.c | 6 +- sys/netinet/udp_usrreq.c | 4 +- sys/netinet6/ah.h | 19 +- sys/netinet6/ah_core.c | 276 +- sys/netinet6/ah_input.c | 309 +- sys/netinet6/ah_output.c | 160 +- sys/netinet6/esp.h | 17 +- sys/netinet6/in6_pcb.c | 4 +- sys/netinet6/in6_pcb.h | 7 +- sys/netinet6/ip6_forward.c | 32 +- sys/netinet6/ip6_output.c | 27 +- sys/netinet6/ipcomp_core.c | 16 +- sys/netinet6/ipcomp_input.c | 99 +- sys/netinet6/ipcomp_output.c | 84 +- sys/netinet6/ipsec.c | 1650 ++++++---- sys/netinet6/ipsec.h | 181 +- sys/netinet6/raw_ip6.c | 4 +- sys/netinet6/udp6_usrreq.c | 4 +- sys/netkey/key.c | 5773 ++++++++++++++++------------------ sys/netkey/key.h | 68 +- sys/netkey/key_debug.c | 283 +- sys/netkey/key_debug.h | 32 +- sys/netkey/key_var.h | 4 +- sys/netkey/keydb.c | 215 ++ sys/netkey/keydb.h | 157 +- sys/netkey/keysock.c | 232 +- sys/netkey/keysock.h | 57 +- sys/netkey/keyv2.h | 167 +- 35 files changed, 5154 insertions(+), 4822 deletions(-) create mode 100644 sys/netkey/keydb.c diff --git a/sys/conf/files b/sys/conf/files index 2967740c7ea5..a0715915cad3 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $NetBSD: files,v 1.346 2000/01/26 06:27:33 thorpej Exp $ +# $NetBSD: files,v 1.347 2000/01/31 14:18:52 itojun Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -602,6 +602,7 @@ file kern/exec_conf.c file kern/exec_ecoff.c exec_ecoff file netkey/key.c ipsec +file netkey/keydb.c ipsec file netkey/key_debug.c ipsec file netkey/keysock.c ipsec diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index e7eb18cb0395..947116af1751 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -1,4 +1,4 @@ -/* $NetBSD: in_pcb.h,v 1.27 1999/07/01 08:12:50 itojun Exp $ */ +/* $NetBSD: in_pcb.h,v 1.28 2000/01/31 14:18:53 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -95,9 +95,7 @@ struct inpcb { int inp_errormtu; /* MTU of last xmit status = EMSGSIZE */ struct inpcbtable *inp_table; #if 1 /*IPSEC*/ - struct secpolicy *inp_sp; /* security policy. It may not be - * used according to policy selection. - */ + struct inpcbpolicy *inp_sp; /* security policy. */ #endif }; #define inp_faddr inp_ip.ip_dst diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 30e4cf1cbce8..6492ac150965 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.94 1999/10/26 09:53:17 itojun Exp $ */ +/* $NetBSD: ip_input.c,v 1.95 2000/01/31 14:18:54 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -1430,18 +1430,21 @@ ip_forward(m, srcrt) if (ipforward_rt.ro_rt) { struct secpolicy *sp; int ipsecerror; - int ipsechdr; + size_t ipsechdr; struct route *ro; sp = ipsec4_getpolicybyaddr(mcopy, - IP_FORWARDING, - &ipsecerror); + IPSEC_DIR_OUTBOUND, + IP_FORWARDING, + &ipsecerror); if (sp == NULL) destifp = ipforward_rt.ro_rt->rt_ifp; else { /* count IPsec header size */ - ipsechdr = ipsec4_hdrsiz(mcopy, NULL); + ipsechdr = ipsec4_hdrsiz(mcopy, + IPSEC_DIR_OUTBOUND, + NULL); /* * find the correct route for outer IPv4 @@ -1454,8 +1457,9 @@ ip_forward(m, srcrt) /*XXX*/ destifp = NULL; if (sp->req != NULL - && sp->req->sa != NULL) { - ro = &sp->req->sa->saidx->sa_route; + && sp->req->sav != NULL + && sp->req->sav->sah != NULL) { + ro = &sp->req->sav->sah->sa_route; if (ro->ro_rt && ro->ro_rt->rt_ifp) { dummyifp.if_mtu = ro->ro_rt->rt_ifp->if_mtu; diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index c7bd3c3ffe29..008b24909932 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_output.c,v 1.65 1999/12/20 05:46:33 itojun Exp $ */ +/* $NetBSD: ip_output.c,v 1.66 2000/01/31 14:18:55 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -434,9 +434,9 @@ sendit: #ifdef IPSEC /* get SP for this packet */ if (so == NULL) - sp = ipsec4_getpolicybyaddr(m, flags, &error); + sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error); else - sp = ipsec4_getpolicybysock(m, so, &error); + sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); if (sp == NULL) { ipsecstat.out_inval++; @@ -939,10 +939,11 @@ ip_ctloutput(op, so, level, optname, mp) #ifdef IPSEC case IP_IPSEC_POLICY: - { + { caddr_t req = NULL; - int len = 0; + size_t len = 0; int priv = 0; + #ifdef __NetBSD__ if (p == 0 || suser(p->p_ucred, &p->p_acflag)) priv = 0; @@ -951,12 +952,11 @@ ip_ctloutput(op, so, level, optname, mp) #else priv = (in6p->in6p_socket->so_state & SS_PRIV); #endif - if (m != 0) { + if (m) { req = mtod(m, caddr_t); len = m->m_len; } - error = ipsec_set_policy(&inp->inp_sp, - optname, req, len, priv); + error = ipsec4_set_policy(inp, optname, req, len, priv); break; } #endif /*IPSEC*/ @@ -1028,8 +1028,17 @@ ip_ctloutput(op, so, level, optname, mp) #ifdef IPSEC case IP_IPSEC_POLICY: - error = ipsec_get_policy(inp->inp_sp, mp); + { + caddr_t req = NULL; + size_t len; + + if (m) { + req = mtod(m, caddr_t); + len = m->m_len; + } + error = ipsec4_get_policy(inp, req, len, mp); break; + } #endif /*IPSEC*/ case IP_MULTICAST_IF: diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 58c208eacc0c..4283d13b15f3 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -1,4 +1,4 @@ -/* $NetBSD: raw_ip.c,v 1.47 1999/12/13 15:17:20 itojun Exp $ */ +/* $NetBSD: raw_ip.c,v 1.48 2000/01/31 14:18:55 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -464,7 +464,7 @@ rip_usrreq(so, req, m, nam, control, p) inp = sotoinpcb(so); inp->inp_ip.ip_p = (long)nam; #ifdef IPSEC - error = ipsec_init_policy(&inp->inp_sp); + error = ipsec_init_policy(so, &inp->inp_sp); if (error != 0) { in_pcbdetach(inp); break; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 97254521fba4..9ca834374bfc 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_input.c,v 1.101 1999/12/22 04:03:02 itojun Exp $ */ +/* $NetBSD: tcp_input.c,v 1.102 2000/01/31 14:18:56 itojun Exp $ */ /* %%% portions-copyright-nrl-95 @@ -2890,27 +2890,22 @@ syn_cache_get(src, dst, th, hlen, tlen, so, m) #endif #ifdef IPSEC - { - struct secpolicy *sp; + /* + * we make a copy of policy, instead of sharing the policy, + * for better behavior in terms of SA lookup and dead SA removal. + */ if (inp) { - sp = ipsec_copy_policy(sotoinpcb(oso)->inp_sp); - if (sp) { - key_freesp(inp->inp_sp); - inp->inp_sp = sp; - } else + /* copy old policy into new socket's */ + if (ipsec_copy_policy(sotoinpcb(oso)->inp_sp, inp->inp_sp)) printf("tcp_input: could not copy policy\n"); } #ifdef INET6 else if (in6p) { - sp = ipsec_copy_policy(sotoin6pcb(oso)->in6p_sp); - if (sp) { - key_freesp(in6p->in6p_sp); - in6p->in6p_sp = sp; - } else + /* copy old policy into new socket's */ + if (ipsec_copy_policy(sotoin6pcb(oso)->in6p_sp, in6p->in6p_sp)) printf("tcp_input: could not copy policy\n"); } #endif - } #endif /* diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 5e4f3691f059..2d71e35ecc12 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_subr.c,v 1.85 1999/12/15 06:28:43 itojun Exp $ */ +/* $NetBSD: tcp_subr.c,v 1.86 2000/01/31 14:18:57 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -1657,7 +1657,8 @@ ipsec4_hdrsiz_tcp(tp) return 0; switch (tp->t_family) { case AF_INET: - hdrsiz = ipsec4_hdrsiz(tp->t_template, inp); + /* XXX: should use currect direction. */ + hdrsiz = ipsec4_hdrsiz(tp->t_template, IPSEC_DIR_OUTBOUND, inp); break; default: hdrsiz = 0; @@ -1679,7 +1680,8 @@ ipsec6_hdrsiz_tcp(tp) return 0; switch (tp->t_family) { case AF_INET6: - hdrsiz = ipsec6_hdrsiz(tp->t_template, in6p); + /* XXX: should use currect direction. */ + hdrsiz = ipsec6_hdrsiz(tp->t_template, IPSEC_DIR_OUTBOUND, in6p); break; case AF_INET: /* mapped address case - tricky */ diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index deddd049ad03..2564278bbffe 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_usrreq.c,v 1.43 1999/12/13 15:17:21 itojun Exp $ */ +/* $NetBSD: tcp_usrreq.c,v 1.44 2000/01/31 14:18:58 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -731,7 +731,7 @@ tcp_attach(so) } #ifdef IPSEC if (inp) { - error = ipsec_init_policy(&inp->inp_sp); + error = ipsec_init_policy(so, &inp->inp_sp); if (error != 0) { in_pcbdetach(inp); return (error); @@ -739,7 +739,7 @@ tcp_attach(so) } #ifdef INET6 else if (in6p) { - error = ipsec_init_policy(&in6p->in6p_sp); + error = ipsec_init_policy(so, &in6p->in6p_sp); if (error != 0) { in6_pcbdetach(in6p); return (error); diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 45a99c5a47fd..6241a7ef858f 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: udp_usrreq.c,v 1.57 2000/01/31 10:39:26 itojun Exp $ */ +/* $NetBSD: udp_usrreq.c,v 1.58 2000/01/31 14:18:58 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -1342,7 +1342,7 @@ udp_usrreq(so, req, m, nam, control, p) inp = sotoinpcb(so); inp->inp_ip.ip_ttl = ip_defttl; #ifdef IPSEC - error = ipsec_init_policy(&inp->inp_sp); + error = ipsec_init_policy(so, &inp->inp_sp); if (error != 0) { in_pcbdetach(inp); break; diff --git a/sys/netinet6/ah.h b/sys/netinet6/ah.h index 8056e9425c2c..51995997a99a 100644 --- a/sys/netinet6/ah.h +++ b/sys/netinet6/ah.h @@ -1,4 +1,4 @@ -/* $NetBSD: ah.h,v 1.7 2000/01/06 07:31:10 itojun Exp $ */ +/* $NetBSD: ah.h,v 1.8 2000/01/31 14:19:00 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -40,7 +40,7 @@ #include "opt_inet.h" #endif -#include /* for struct secas */ +#include /* for struct secasvar */ struct ah { u_int8_t ah_nxt; /* Next Header */ @@ -60,16 +60,16 @@ struct newah { }; struct ah_algorithm_state { - struct secas *sa; + struct secasvar *sav; void* foo; /*per algorithm data - maybe*/ }; struct ah_algorithm { - int (*sumsiz) __P((struct secas *)); - int (*mature) __P((struct secas *)); + int (*sumsiz) __P((struct secasvar *)); + int (*mature) __P((struct secasvar *)); int keymin; /* in bits */ int keymax; /* in bits */ - void (*init) __P((struct ah_algorithm_state *, struct secas *)); + void (*init) __P((struct ah_algorithm_state *, struct secasvar *)); void (*update) __P((struct ah_algorithm_state *, caddr_t, size_t)); void (*result) __P((struct ah_algorithm_state *, caddr_t)); }; @@ -85,21 +85,20 @@ struct in6pcb; #endif /* cksum routines */ -extern int ah_hdrlen __P((struct secas *)); +extern int ah_hdrlen __P((struct secasvar *)); extern size_t ah_hdrsiz __P((struct ipsecrequest *)); extern void ah4_input __P((struct mbuf *, ...)); -struct secasb; extern int ah4_output __P((struct mbuf *, struct ipsecrequest *)); extern int ah4_calccksum __P((struct mbuf *, caddr_t, - struct ah_algorithm *, struct secas *)); + struct ah_algorithm *, struct secasvar *)); #ifdef INET6 extern int ah6_input __P((struct mbuf **, int *, int)); extern int ah6_output __P((struct mbuf *, u_char *, struct mbuf *, struct ipsecrequest *)); extern int ah6_calccksum __P((struct mbuf *, caddr_t, - struct ah_algorithm *, struct secas *)); + struct ah_algorithm *, struct secasvar *)); #endif /* INET6 */ #endif /*_KERNEL*/ diff --git a/sys/netinet6/ah_core.c b/sys/netinet6/ah_core.c index 5e6fe10b1c62..c38614f0ae35 100644 --- a/sys/netinet6/ah_core.c +++ b/sys/netinet6/ah_core.c @@ -1,4 +1,4 @@ -/* $NetBSD: ah_core.c,v 1.14 2000/01/16 18:06:03 itojun Exp $ */ +/* $NetBSD: ah_core.c,v 1.15 2000/01/31 14:19:01 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -61,11 +62,9 @@ #include #include #include -#include #ifdef INET6 #include -#include #include #include #endif @@ -77,9 +76,19 @@ #endif #include #include +#ifdef HAVE_MD5 #include +#else +#include +#endif +#ifdef HAVE_SHA1 #include #define SHA1_RESULTLEN 20 +#else +#include +#endif + +#include #define HMACSIZE 16 @@ -88,34 +97,34 @@ static char zerobuf[ZEROBUFLEN]; #endif -static int ah_sumsiz_1216 __P((struct secas *)); -static int ah_sumsiz_zero __P((struct secas *)); -static int ah_none_mature __P((struct secas *)); +static int ah_sumsiz_1216 __P((struct secasvar *)); +static int ah_sumsiz_zero __P((struct secasvar *)); +static int ah_none_mature __P((struct secasvar *)); static void ah_none_init __P((struct ah_algorithm_state *, - struct secas *)); + struct secasvar *)); static void ah_none_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_none_result __P((struct ah_algorithm_state *, caddr_t)); -static int ah_keyed_md5_mature __P((struct secas *)); +static int ah_keyed_md5_mature __P((struct secasvar *)); static void ah_keyed_md5_init __P((struct ah_algorithm_state *, - struct secas *)); + struct secasvar *)); static void ah_keyed_md5_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_keyed_md5_result __P((struct ah_algorithm_state *, caddr_t)); -static int ah_keyed_sha1_mature __P((struct secas *)); +static int ah_keyed_sha1_mature __P((struct secasvar *)); static void ah_keyed_sha1_init __P((struct ah_algorithm_state *, - struct secas *)); + struct secasvar *)); static void ah_keyed_sha1_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_keyed_sha1_result __P((struct ah_algorithm_state *, caddr_t)); -static int ah_hmac_md5_mature __P((struct secas *)); +static int ah_hmac_md5_mature __P((struct secasvar *)); static void ah_hmac_md5_init __P((struct ah_algorithm_state *, - struct secas *)); + struct secasvar *)); static void ah_hmac_md5_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_hmac_md5_result __P((struct ah_algorithm_state *, caddr_t)); -static int ah_hmac_sha1_mature __P((struct secas *)); +static int ah_hmac_sha1_mature __P((struct secasvar *)); static void ah_hmac_sha1_init __P((struct ah_algorithm_state *, - struct secas *)); + struct secasvar *)); static void ah_hmac_sha1_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_hmac_sha1_result __P((struct ah_algorithm_state *, caddr_t)); @@ -137,41 +146,42 @@ struct ah_algorithm ah_algorithms[] = { }; static int -ah_sumsiz_1216(sa) - struct secas *sa; +ah_sumsiz_1216(sav) + struct secasvar *sav; { - if (!sa) + if (!sav) return -1; - if (sa->flags & SADB_X_EXT_OLD) + if (sav->flags & SADB_X_EXT_OLD) return 16; else return 12; } static int -ah_sumsiz_zero(sa) - struct secas *sa; +ah_sumsiz_zero(sav) + struct secasvar *sav; { - if (!sa) + if (!sav) return -1; return 0; } static int -ah_none_mature(sa) - struct secas *sa; +ah_none_mature(sav) + struct secasvar *sav; { - if (sa->type == SADB_SATYPE_AH) { - printf("ah_none_mature: protocol and algorithm mismatch.\n"); + if (sav->sah->saidx.proto == IPPROTO_AH) { + ipseclog((LOG_ERR, + "ah_none_mature: protocol and algorithm mismatch.\n")); return 1; } return 0; } static void -ah_none_init(state, sa) +ah_none_init(state, sav) struct ah_algorithm_state *state; - struct secas *sa; + struct secasvar *sav; { state->foo = NULL; } @@ -192,30 +202,30 @@ ah_none_result(state, addr) } static int -ah_keyed_md5_mature(sa) - struct secas *sa; +ah_keyed_md5_mature(sav) + struct secasvar *sav; { /* anything is okay */ return 0; } static void -ah_keyed_md5_init(state, sa) +ah_keyed_md5_init(state, sav) struct ah_algorithm_state *state; - struct secas *sa; + struct secasvar *sav; { if (!state) panic("ah_keyed_md5_init: what?"); - state->sa = sa; + state->sav = sav; state->foo = (void *)malloc(sizeof(MD5_CTX), M_TEMP, M_NOWAIT); if (state->foo == NULL) panic("ah_keyed_md5_init: what?"); MD5Init((MD5_CTX *)state->foo); - if (state->sa) { + if (state->sav) { MD5Update((MD5_CTX *)state->foo, - (u_int8_t *)_KEYBUF(state->sa->key_auth), - (u_int)_KEYLEN(state->sa->key_auth)); + (u_int8_t *)_KEYBUF(state->sav->key_auth), + (u_int)_KEYLEN(state->sav->key_auth)); { /* @@ -227,11 +237,11 @@ ah_keyed_md5_init(state, sa) size_t keybitlen; u_int8_t buf[32]; - if (_KEYLEN(state->sa->key_auth) < 56) - padlen = 64 - 8 - _KEYLEN(state->sa->key_auth); + if (_KEYLEN(state->sav->key_auth) < 56) + padlen = 64 - 8 - _KEYLEN(state->sav->key_auth); else - padlen = 64 + 64 - 8 - _KEYLEN(state->sa->key_auth); - keybitlen = _KEYLEN(state->sa->key_auth); + padlen = 64 + 64 - 8 - _KEYLEN(state->sav->key_auth); + keybitlen = _KEYLEN(state->sav->key_auth); keybitlen *= 8; buf[0] = 0x80; @@ -278,10 +288,10 @@ ah_keyed_md5_result(state, addr) if (!state) panic("ah_keyed_md5_result: what?"); - if (state->sa) { + if (state->sav) { MD5Update((MD5_CTX *)state->foo, - (u_int8_t *)_KEYBUF(state->sa->key_auth), - (u_int)_KEYLEN(state->sa->key_auth)); + (u_int8_t *)_KEYBUF(state->sav->key_auth), + (u_int)_KEYLEN(state->sav->key_auth)); } MD5Final(&digest[0], (MD5_CTX *)state->foo); free(state->foo, M_TEMP); @@ -289,20 +299,21 @@ ah_keyed_md5_result(state, addr) } static int -ah_keyed_sha1_mature(sa) - struct secas *sa; +ah_keyed_sha1_mature(sav) + struct secasvar *sav; { struct ah_algorithm *algo; - if (!sa->key_auth) { - printf("esp_keyed_sha1_mature: no key is given.\n"); + if (!sav->key_auth) { + ipseclog((LOG_ERR, "ah_keyed_sha1_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sa->alg_auth]; - if (sa->key_auth->sadb_key_bits < algo->keymin - || algo->keymax < sa->key_auth->sadb_key_bits) { - printf("ah_keyed_sha1_mature: invalid key length %d.\n", - sa->key_auth->sadb_key_bits); + algo = &ah_algorithms[sav->alg_auth]; + if (sav->key_auth->sadb_key_bits < algo->keymin + || algo->keymax < sav->key_auth->sadb_key_bits) { + ipseclog((LOG_ERR, + "ah_keyed_sha1_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); return 1; } @@ -310,16 +321,16 @@ ah_keyed_sha1_mature(sa) } static void -ah_keyed_sha1_init(state, sa) +ah_keyed_sha1_init(state, sav) struct ah_algorithm_state *state; - struct secas *sa; + struct secasvar *sav; { SHA1_CTX *ctxt; if (!state) panic("ah_keyed_sha1_init: what?"); - state->sa = sa; + state->sav = sav; state->foo = (void *)malloc(sizeof(SHA1_CTX), M_TEMP, M_NOWAIT); if (!state->foo) panic("ah_keyed_sha1_init: what?"); @@ -327,9 +338,9 @@ ah_keyed_sha1_init(state, sa) ctxt = (SHA1_CTX *)state->foo; SHA1Init(ctxt); - if (state->sa) { - SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sa->key_auth), - (u_int)_KEYLEN(state->sa->key_auth)); + if (state->sav) { + SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth), + (u_int)_KEYLEN(state->sav->key_auth)); { /* @@ -339,11 +350,11 @@ ah_keyed_sha1_init(state, sa) size_t keybitlen; u_int8_t buf[32]; - if (_KEYLEN(state->sa->key_auth) < 56) - padlen = 64 - 8 - _KEYLEN(state->sa->key_auth); + if (_KEYLEN(state->sav->key_auth) < 56) + padlen = 64 - 8 - _KEYLEN(state->sav->key_auth); else - padlen = 64 + 64 - 8 - _KEYLEN(state->sa->key_auth); - keybitlen = _KEYLEN(state->sa->key_auth); + padlen = 64 + 64 - 8 - _KEYLEN(state->sav->key_auth); + keybitlen = _KEYLEN(state->sav->key_auth); keybitlen *= 8; buf[0] = 0x80; @@ -395,9 +406,9 @@ ah_keyed_sha1_result(state, addr) panic("ah_keyed_sha1_result: what?"); ctxt = (SHA1_CTX *)state->foo; - if (state->sa) { - SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sa->key_auth), - (u_int)_KEYLEN(state->sa->key_auth)); + if (state->sav) { + SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth), + (u_int)_KEYLEN(state->sav->key_auth)); } SHA1Final((caddr_t)&digest[0], ctxt); bcopy(&digest[0], (void *)addr, HMACSIZE); @@ -406,20 +417,21 @@ ah_keyed_sha1_result(state, addr) } static int -ah_hmac_md5_mature(sa) - struct secas *sa; +ah_hmac_md5_mature(sav) + struct secasvar *sav; { struct ah_algorithm *algo; - if (!sa->key_auth) { - printf("esp_hmac_md5_mature: no key is given.\n"); + if (!sav->key_auth) { + ipseclog((LOG_ERR, "ah_hmac_md5_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sa->alg_auth]; - if (sa->key_auth->sadb_key_bits < algo->keymin - || algo->keymax < sa->key_auth->sadb_key_bits) { - printf("ah_hmac_md5_mature: invalid key length %d.\n", - sa->key_auth->sadb_key_bits); + algo = &ah_algorithms[sav->alg_auth]; + if (sav->key_auth->sadb_key_bits < algo->keymin + || algo->keymax < sav->key_auth->sadb_key_bits) { + ipseclog((LOG_ERR, + "ah_hmac_md5_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); return 1; } @@ -427,9 +439,9 @@ ah_hmac_md5_mature(sa) } static void -ah_hmac_md5_init(state, sa) +ah_hmac_md5_init(state, sav) struct ah_algorithm_state *state; - struct secas *sa; + struct secasvar *sav; { u_char *ipad; u_char *opad; @@ -442,7 +454,7 @@ ah_hmac_md5_init(state, sa) if (!state) panic("ah_hmac_md5_init: what?"); - state->sa = sa; + state->sav = sav; state->foo = (void *)malloc(64 + 64 + sizeof(MD5_CTX), M_TEMP, M_NOWAIT); if (!state->foo) panic("ah_hmac_md5_init: what?"); @@ -452,16 +464,16 @@ ah_hmac_md5_init(state, sa) ctxt = (MD5_CTX *)(opad + 64); /* compress the key if necessery */ - if (64 < _KEYLEN(state->sa->key_auth)) { + if (64 < _KEYLEN(state->sav->key_auth)) { MD5Init(ctxt); - MD5Update(ctxt, _KEYBUF(state->sa->key_auth), - _KEYLEN(state->sa->key_auth)); + MD5Update(ctxt, _KEYBUF(state->sav->key_auth), + _KEYLEN(state->sav->key_auth)); MD5Final(&tk[0], ctxt); key = &tk[0]; keylen = 16; } else { - key = _KEYBUF(state->sa->key_auth); - keylen = _KEYLEN(state->sa->key_auth); + key = _KEYBUF(state->sav->key_auth); + keylen = _KEYLEN(state->sav->key_auth); } bzero(ipad, 64); @@ -521,20 +533,21 @@ ah_hmac_md5_result(state, addr) } static int -ah_hmac_sha1_mature(sa) - struct secas *sa; +ah_hmac_sha1_mature(sav) + struct secasvar *sav; { struct ah_algorithm *algo; - if (!sa->key_auth) { - printf("esp_hmac_sha1_mature: no key is given.\n"); + if (!sav->key_auth) { + ipseclog((LOG_ERR, "ah_hmac_sha1_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sa->alg_auth]; - if (sa->key_auth->sadb_key_bits < algo->keymin - || algo->keymax < sa->key_auth->sadb_key_bits) { - printf("ah_hmac_sha1_mature: invalid key length %d.\n", - sa->key_auth->sadb_key_bits); + algo = &ah_algorithms[sav->alg_auth]; + if (sav->key_auth->sadb_key_bits < algo->keymin + || algo->keymax < sav->key_auth->sadb_key_bits) { + ipseclog((LOG_ERR, + "ah_hmac_sha1_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); return 1; } @@ -542,9 +555,9 @@ ah_hmac_sha1_mature(sa) } static void -ah_hmac_sha1_init(state, sa) +ah_hmac_sha1_init(state, sav) struct ah_algorithm_state *state; - struct secas *sa; + struct secasvar *sav; { u_char *ipad; u_char *opad; @@ -557,7 +570,7 @@ ah_hmac_sha1_init(state, sa) if (!state) panic("ah_hmac_sha1_init: what?"); - state->sa = sa; + state->sav = sav; state->foo = (void *)malloc(64 + 64 + sizeof(SHA1_CTX), M_TEMP, M_NOWAIT); if (!state->foo) @@ -568,16 +581,16 @@ ah_hmac_sha1_init(state, sa) ctxt = (SHA1_CTX *)(opad + 64); /* compress the key if necessery */ - if (64 < _KEYLEN(state->sa->key_auth)) { + if (64 < _KEYLEN(state->sav->key_auth)) { SHA1Init(ctxt); - SHA1Update(ctxt, _KEYBUF(state->sa->key_auth), - _KEYLEN(state->sa->key_auth)); + SHA1Update(ctxt, _KEYBUF(state->sav->key_auth), + _KEYLEN(state->sav->key_auth)); SHA1Final(&tk[0], ctxt); key = &tk[0]; keylen = SHA1_RESULTLEN; } else { - key = _KEYBUF(state->sa->key_auth); - keylen = _KEYLEN(state->sa->key_auth); + key = _KEYBUF(state->sav->key_auth); + keylen = _KEYLEN(state->sav->key_auth); } bzero(ipad, 64); @@ -643,11 +656,11 @@ ah_hmac_sha1_result(state, addr) * go generate the checksum. */ int -ah4_calccksum(m0, ahdat, algo, sa) +ah4_calccksum(m0, ahdat, algo, sav) struct mbuf *m0; caddr_t ahdat; struct ah_algorithm *algo; - struct secas *sa; + struct secasvar *sav; { struct mbuf *m; int hdrtype; @@ -664,7 +677,7 @@ ah4_calccksum(m0, ahdat, algo, sa) p = mtod(m, u_char *); - (algo->init)(&algos, sa); + (algo->init)(&algos, sav); advancewidth = 0; /*safety*/ @@ -728,10 +741,11 @@ again: break; } if (l <= 0 || hlen - i < l) { - printf("ah4_input: invalid IP option " - "(type=%02x len=%02x)\n", - p[i + IPOPT_OPTVAL], - p[i + IPOPT_OLEN]); + ipseclog((LOG_ERR, + "ah4_calccksum: invalid IP option " + "(type=%02x len=%02x)\n", + p[i + IPOPT_OPTVAL], + p[i + IPOPT_OLEN])); break; } if (skip) { @@ -758,13 +772,13 @@ again: int siz; int hdrsiz; - hdrsiz = (sa->flags & SADB_X_EXT_OLD) ? + hdrsiz = (sav->flags & SADB_X_EXT_OLD) ? sizeof(struct ah) : sizeof(struct newah); (algo->update)(&algos, p, hdrsiz); /* key data region. */ - siz = (*algo->sumsiz)(sa); + siz = (*algo->sumsiz)(sav); bzero(&dummy[0], sizeof(dummy)); while (sizeof(dummy) <= siz) { (algo->update)(&algos, dummy, sizeof(dummy)); @@ -775,26 +789,26 @@ again: (algo->update)(&algos, dummy, siz); /* padding region, just in case */ - siz = (((struct ah *)p)->ah_len << 2) - (*algo->sumsiz)(sa); - if ((sa->flags & SADB_X_EXT_OLD) == 0) + siz = (((struct ah *)p)->ah_len << 2) - (*algo->sumsiz)(sav); + if ((sav->flags & SADB_X_EXT_OLD) == 0) siz -= 4; /* sequence number field */ if (0 < siz) { /* RFC 1826 */ - (algo->update)(&algos, p + hdrsiz + (*algo->sumsiz)(sa), + (algo->update)(&algos, p + hdrsiz + (*algo->sumsiz)(sav), siz); } hdrtype = ((struct ah *)p)->ah_nxt; advancewidth = hdrsiz; advancewidth += ((struct ah *)p)->ah_len << 2; - if ((sa->flags & SADB_X_EXT_OLD) == 0) + if ((sav->flags & SADB_X_EXT_OLD) == 0) advancewidth -= 4; /* sequence number field */ break; } default: - printf("ah4_calccksum: unexpected hdrtype=%x; " - "treating rest as payload\n", hdrtype); + ipseclog((LOG_DEBUG, "ah4_calccksum: unexpected hdrtype=%x; " + "treating rest as payload\n", hdrtype)); /*fall through*/ case IPPROTO_ICMP: case IPPROTO_IGMP: @@ -831,7 +845,8 @@ again: if (m) p = mtod(m, u_char *); else { - printf("ERR: hit the end-of-mbuf...\n"); + ipseclog((LOG_DEBUG, + "hit the end-of-mbuf...\n")); p = NULL; } } @@ -843,7 +858,7 @@ again: /* for HMAC algorithms... */ (algo->result)(&algos, &sumbuf[0]); - bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sa)); + bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); return error; } @@ -854,11 +869,11 @@ again: * except AH itself. */ int -ah6_calccksum(m0, ahdat, algo, sa) +ah6_calccksum(m0, ahdat, algo, sav) struct mbuf *m0; caddr_t ahdat; struct ah_algorithm *algo; - struct secas *sa; + struct secasvar *sav; { struct mbuf *m; int hdrtype; @@ -876,7 +891,7 @@ ah6_calccksum(m0, ahdat, algo, sa) p = mtod(m, u_char *); - (algo->init)(&algos, sa); + (algo->init)(&algos, sav); advancewidth = 0; /*safety*/ nest = 0; @@ -917,13 +932,13 @@ again: int siz; int hdrsiz; - hdrsiz = (sa->flags & SADB_X_EXT_OLD) ? + hdrsiz = (sav->flags & SADB_X_EXT_OLD) ? sizeof(struct ah) : sizeof(struct newah); (algo->update)(&algos, p, hdrsiz); /* key data region. */ - siz = (*algo->sumsiz)(sa); + siz = (*algo->sumsiz)(sav); bzero(&dummy[0], 4); while (4 <= siz) { (algo->update)(&algos, dummy, 4); @@ -934,18 +949,18 @@ again: (algo->update)(&algos, dummy, siz); /* padding region, just in case */ - siz = (((struct ah *)p)->ah_len << 2) - (*algo->sumsiz)(sa); - if ((sa->flags & SADB_X_EXT_OLD) == 0) + siz = (((struct ah *)p)->ah_len << 2) - (*algo->sumsiz)(sav); + if ((sav->flags & SADB_X_EXT_OLD) == 0) siz -= 4; /* sequence number field */ if (0 < siz) { - (algo->update)(&algos, p + hdrsiz + (*algo->sumsiz)(sa), + (algo->update)(&algos, p + hdrsiz + (*algo->sumsiz)(sav), siz); } hdrtype = ((struct ah *)p)->ah_nxt; advancewidth = hdrsiz; advancewidth += ((struct ah *)p)->ah_len << 2; - if ((sa->flags & SADB_X_EXT_OLD) == 0) + if ((sav->flags & SADB_X_EXT_OLD) == 0) advancewidth -= 4; /* sequence number field */ break; } @@ -1068,12 +1083,12 @@ again: break; } default: - printf("ah6_calccksum: unexpected hdrtype=%x; " - "treating rest as payload\n", hdrtype); + ipseclog((LOG_DEBUG, "ah6_calccksum: unexpected hdrtype=%x; " + "treating rest as payload\n", hdrtype)); /*fall through*/ case IPPROTO_ICMP: case IPPROTO_IGMP: - case IPPROTO_IPIP: /*?*/ + case IPPROTO_IPIP: case IPPROTO_IPV6: case IPPROTO_ICMPV6: case IPPROTO_UDP: @@ -1104,7 +1119,8 @@ again: if (m) p = mtod(m, u_char *); else { - printf("ERR: hit the end-of-mbuf...\n"); + ipseclog((LOG_DEBUG, + "hit the end-of-mbuf...\n")); p = NULL; } } @@ -1116,7 +1132,7 @@ again: /* for HMAC algorithms... */ (algo->result)(&algos, &sumbuf[0]); - bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sa)); + bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); return(0); diff --git a/sys/netinet6/ah_input.c b/sys/netinet6/ah_input.c index 2ae1f2bc9024..040d5e0f215c 100644 --- a/sys/netinet6/ah_input.c +++ b/sys/netinet6/ah_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: ah_input.c,v 1.6 2000/01/06 07:31:11 itojun Exp $ */ +/* $NetBSD: ah_input.c,v 1.7 2000/01/31 14:19:01 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -61,7 +61,6 @@ #ifdef INET6 #include -#include #include #include #endif @@ -74,9 +73,7 @@ #include -#ifdef __NetBSD__ -#define ovbcopy bcopy -#endif +#include #ifdef INET extern struct protosw inetsw[]; @@ -98,7 +95,7 @@ ah4_input(m, va_alist) size_t siz; size_t siz1; u_char *cksum; - struct secas *sa = NULL; + struct secasvar *sav = NULL; u_int16_t nxt; size_t hlen; int s; @@ -110,11 +107,12 @@ ah4_input(m, va_alist) proto = va_arg(ap, int); va_end(ap); +#ifndef PULLDOWN_TEST if (m->m_len < off + sizeof(struct newah)) { m = m_pullup(m, off + sizeof(struct newah)); if (!m) { - printf("IPv4 AH input: can't pullup;" - "dropping the packet for simplicity\n"); + ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" + "dropping the packet for simplicity\n")); ipsecstat.in_inval++; goto fail; } @@ -122,6 +120,16 @@ ah4_input(m, va_alist) ip = mtod(m, struct ip *); ah = (struct ah *)(((caddr_t)ip) + off); +#else + ip = mtod(m, struct ip *); + IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); + if (ah == NULL) { + ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" + "dropping the packet for simplicity\n")); + ipsecstat.in_inval++; + goto fail; + } +#endif nxt = ah->ah_nxt; #ifdef _IP_VHL hlen = IP_VHL_HL(ip->ip_vhl) << 2; @@ -132,37 +140,36 @@ ah4_input(m, va_alist) /* find the sassoc. */ spi = ah->ah_spi; - if ((sa = key_allocsa(AF_INET, + if ((sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, IPPROTO_AH, spi)) == 0) { - printf("IPv4 AH input: no key association found for spi %u;" - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + ipseclog((LOG_WARNING, + "IPv4 AH input: no key association found for spi %u\n", + (u_int32_t)ntohl(spi))); ipsecstat.in_nosa++; goto fail; } KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah4_input called to allocate SA:%p\n", sa)); - if (sa->state != SADB_SASTATE_MATURE - && sa->state != SADB_SASTATE_DYING) { - printf("IPv4 AH input: non-mature/dying SA found for spi %u; " - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + printf("DP ah4_input called to allocate SA:%p\n", sav)); + if (sav->state != SADB_SASTATE_MATURE + && sav->state != SADB_SASTATE_DYING) { + ipseclog((LOG_DEBUG, + "IPv4 AH input: non-mature/dying SA found for spi %u\n", + (u_int32_t)ntohl(spi))); ipsecstat.in_badspi++; goto fail; } - if (sa->alg_auth == SADB_AALG_NONE) { - printf("IPv4 AH input: unspecified authentication algorithm " - "for spi %u;" - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + if (sav->alg_auth == SADB_AALG_NONE) { + ipseclog((LOG_DEBUG, "IPv4 AH input: " + "unspecified authentication algorithm for spi %u\n", + (u_int32_t)ntohl(spi))); ipsecstat.in_badspi++; goto fail; } - algo = &ah_algorithms[sa->alg_auth]; + algo = &ah_algorithms[sav->alg_auth]; - siz = (*algo->sumsiz)(sa); + siz = (*algo->sumsiz)(sav); siz1 = ((siz + 3) & ~(4 - 1)); /* @@ -171,22 +178,22 @@ ah4_input(m, va_alist) { int sizoff; - sizoff = (sa->flags & SADB_X_EXT_OLD) ? 0 : 4; + sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; if ((ah->ah_len << 2) - sizoff != siz1) { - log(LOG_NOTICE, "sum length mismatch in IPv4 AH input " + ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input " "(%d should be %u): %s\n", (ah->ah_len << 2) - sizoff, (unsigned int)siz1, - ipsec4_logpacketstr(ip, spi)); + ipsec4_logpacketstr(ip, spi))); ipsecstat.in_inval++; goto fail; } +#ifndef PULLDOWN_TEST if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) { m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1); if (!m) { - printf("IPv4 AH input: can't pullup;" - "dropping the packet for simplicity\n"); + ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); ipsecstat.in_inval++; goto fail; } @@ -194,19 +201,28 @@ ah4_input(m, va_alist) ip = mtod(m, struct ip *); ah = (struct ah *)(((caddr_t)ip) + off); } +#else + IP6_EXTHDR_GET(ah, struct ah *, m, off, + sizeof(struct ah) + sizoff + siz1); + if (ah == NULL) { + ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); + ipsecstat.in_inval++; + goto fail; + } +#endif } /* * check for sequence number. */ - if ((sa->flags & SADB_X_EXT_OLD) == 0 && sa->replay) { - if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sa)) + if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { + if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav)) ; /*okey*/ else { ipsecstat.in_ahreplay++; - log(LOG_AUTH, "replay packet in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), - ipsec_logsastr(sa)); + ipseclog((LOG_WARNING, + "replay packet in IPv4 AH input: %s %s\n", + ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); goto fail; } } @@ -217,7 +233,8 @@ ah4_input(m, va_alist) */ cksum = malloc(siz1, M_TEMP, M_NOWAIT); if (!cksum) { - printf("IPv4 AH input: couldn't alloc temporary region for cksum\n"); + ipseclog((LOG_DEBUG, "IPv4 AH input: " + "couldn't alloc temporary region for cksum\n")); ipsecstat.in_inval++; goto fail; } @@ -231,12 +248,12 @@ ah4_input(m, va_alist) ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); #endif - if (ah4_calccksum(m, (caddr_t)cksum, algo, sa)) { + if (ah4_calccksum(m, (caddr_t)cksum, algo, sav)) { free(cksum, M_TEMP); ipsecstat.in_inval++; goto fail; } - ipsecstat.in_ahhist[sa->alg_auth]++; + ipsecstat.in_ahhist[sav->alg_auth]++; #if 1 /* * flip them back. @@ -249,7 +266,7 @@ ah4_input(m, va_alist) { caddr_t sumpos = NULL; - if (sa->flags & SADB_X_EXT_OLD) { + if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ sumpos = (caddr_t)(ah + 1); } else { @@ -258,9 +275,9 @@ ah4_input(m, va_alist) } if (bcmp(sumpos, cksum, siz) != 0) { - log(LOG_AUTH, "checksum mismatch in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), - ipsec_logsastr(sa)); + ipseclog((LOG_WARNING, + "checksum mismatch in IPv4 AH input: %s %s\n", + ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); free(cksum, M_TEMP); ipsecstat.in_ahauthfail++; goto fail; @@ -281,14 +298,14 @@ ah4_input(m, va_alist) struct ip *nip; size_t sizoff; - sizoff = (sa->flags & SADB_X_EXT_OLD) ? 0 : 4; + sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) { m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1 + hlen); if (!m) { - printf("IPv4 AH input: can't pullup;" - "dropping the packet for simplicity\n"); + ipseclog((LOG_DEBUG, + "IPv4 AH input: can't pullup\n")); ipsecstat.in_inval++; goto fail; } @@ -312,27 +329,30 @@ ah4_input(m, va_alist) if (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) { #if 0 - printf("IPv4 AH input: authentication succeess\n"); -#else - ; + ipseclog((LOG_DEBUG, + "IPv4 AH input: authentication succeess\n")); #endif ipsecstat.in_ahauthsucc++; } else { - log(LOG_AUTH, "authentication failed in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), - ipsec_logsastr(sa)); + ipseclog((LOG_WARNING, + "authentication failed in IPv4 AH input: %s %s\n", + ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); ipsecstat.in_ahauthfail++; + goto fail; } /* * update sequence number. */ - if ((sa->flags & SADB_X_EXT_OLD) == 0 && sa->replay) { - (void)ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sa); + if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { + if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { + ipsecstat.in_ahreplay++; + goto fail; + } } /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec4_tunnel_validate(ip, nxt, sa) && nxt == IPPROTO_IPV4) { + if (ipsec4_tunnel_validate(ip, nxt, sav) && nxt == IPPROTO_IPV4) { /* * strip off all the headers that precedes AH. * IP xx AH IP' payload -> IP' payload @@ -344,7 +364,7 @@ ah4_input(m, va_alist) u_int8_t tos; tos = ip->ip_tos; - if (sa->flags & SADB_X_EXT_OLD) { + if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ stripsiz = sizeof(struct ah) + siz1; } else { @@ -362,11 +382,11 @@ ah4_input(m, va_alist) ip = mtod(m, struct ip *); /* ECN consideration. */ ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos); - if (!key_checktunnelsanity(sa, AF_INET, + if (!key_checktunnelsanity(sav, AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { - log(LOG_NOTICE, "ipsec tunnel address mismatch in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), - ipsec_logsastr(sa)); + ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " + "in IPv4 AH input: %s %s\n", + ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); ipsecstat.in_inval++; goto fail; } @@ -403,7 +423,7 @@ ah4_input(m, va_alist) m->m_flags &= ~M_AUTHIPDGM; #endif - key_sa_recordxfer(sa, m); + key_sa_recordxfer(sav, m); s = splimp(); if (IF_QFULL(&ipintrq)) { @@ -423,7 +443,7 @@ ah4_input(m, va_alist) */ size_t stripsiz = 0; - if (sa->flags & SADB_X_EXT_OLD) { + if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ stripsiz = sizeof(struct ah) + siz1; } else { @@ -431,6 +451,7 @@ ah4_input(m, va_alist) stripsiz = sizeof(struct newah) + siz1; } +#ifndef PULLDOWN_TEST ip = mtod(m, struct ip *); ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off); m->m_data += stripsiz; @@ -447,7 +468,9 @@ ah4_input(m, va_alist) #endif ip->ip_p = nxt; /* forget about IP hdr checksum, the check has already been passed */ - +#else + off += stripsiz; +#endif if (nxt != IPPROTO_DONE) (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); else @@ -455,19 +478,19 @@ ah4_input(m, va_alist) m = NULL; } - if (sa) { + if (sav) { KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah4_input call free SA:%p\n", sa)); - key_freesa(sa); + printf("DP ah4_input call free SA:%p\n", sav)); + key_freesav(sav); } ipsecstat.in_success++; return; fail: - if (sa) { + if (sav) { KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah4_input call free SA:%p\n", sa)); - key_freesa(sa); + printf("DP ah4_input call free SA:%p\n", sav)); + key_freesav(sav); } if (m) m_freem(m); @@ -490,14 +513,23 @@ ah6_input(mp, offp, proto) size_t siz; size_t siz1; u_char *cksum; - struct secas *sa = NULL; + struct secasvar *sav = NULL; u_int16_t nxt; int s; + ip6 = mtod(m, struct ip6_hdr *); +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE); - ip6 = mtod(m, struct ip6_hdr *); ah = (struct ah *)(((caddr_t)ip6) + off); +#else + IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); + if (ah == NULL) { + ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n")); + ipsecstat.in_inval++; + return IPPROTO_DONE; + } +#endif nxt = ah->ah_nxt; @@ -505,42 +537,42 @@ ah6_input(mp, offp, proto) spi = ah->ah_spi; if (ntohs(ip6->ip6_plen) == 0) { - printf("IPv6 AH input: AH with IPv6 jumbogram is not supported.\n"); + ipseclog((LOG_ERR, "IPv6 AH input: " + "AH with IPv6 jumbogram is not supported.\n")); ipsec6stat.in_inval++; goto fail; } - if ((sa = key_allocsa(AF_INET6, + if ((sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, IPPROTO_AH, spi)) == 0) { - printf("IPv6 AH input: no key association found for spi %u;" - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + ipseclog((LOG_WARNING, + "IPv6 AH input: no key association found for spi %u\n", + (u_int32_t)ntohl(spi))); ipsec6stat.in_nosa++; goto fail; } KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah6_input called to allocate SA:%p\n", sa)); - if (sa->state != SADB_SASTATE_MATURE - && sa->state != SADB_SASTATE_DYING) { - printf("IPv6 AH input: non-mature/dying SA found for spi %u; " - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + printf("DP ah6_input called to allocate SA:%p\n", sav)); + if (sav->state != SADB_SASTATE_MATURE + && sav->state != SADB_SASTATE_DYING) { + ipseclog((LOG_DEBUG, + "IPv6 AH input: non-mature/dying SA found for spi %u; ", + (u_int32_t)ntohl(spi))); ipsec6stat.in_badspi++; goto fail; } - if (sa->alg_auth == SADB_AALG_NONE) { - printf("IPv6 AH input: unspecified authentication algorithm " - "for spi %u;" - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + if (sav->alg_auth == SADB_AALG_NONE) { + ipseclog((LOG_DEBUG, "IPv6 AH input: " + "unspecified authentication algorithm for spi %u\n", + (u_int32_t)ntohl(spi))); ipsec6stat.in_badspi++; goto fail; } - algo = &ah_algorithms[sa->alg_auth]; + algo = &ah_algorithms[sav->alg_auth]; - siz = (*algo->sumsiz)(sa); + siz = (*algo->sumsiz)(sav); siz1 = ((siz + 3) & ~(4 - 1)); /* @@ -549,30 +581,42 @@ ah6_input(mp, offp, proto) { int sizoff; - sizoff = (sa->flags & SADB_X_EXT_OLD) ? 0 : 4; + sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; if ((ah->ah_len << 2) - sizoff != siz1) { - log(LOG_NOTICE, "sum length mismatch in IPv6 AH input " + ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input " "(%d should be %u): %s\n", (ah->ah_len << 2) - sizoff, (unsigned int)siz1, - ipsec6_logpacketstr(ip6, spi)); + ipsec6_logpacketstr(ip6, spi))); ipsec6stat.in_inval++; goto fail; } +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE); +#else + IP6_EXTHDR_GET(ah, struct ah *, m, off, + sizeof(struct ah) + sizoff + siz1); + if (ah == NULL) { + ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part")); + ipsecstat.in_inval++; + m = NULL; + goto fail; + } +#endif } /* * check for sequence number. */ - if ((sa->flags & SADB_X_EXT_OLD) == 0 && sa->replay) { - if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sa)) + if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { + if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav)) ; /*okey*/ else { ipsec6stat.in_ahreplay++; - log(LOG_AUTH, "replay packet in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sa)); + ipseclog((LOG_WARNING, + "replay packet in IPv6 AH input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav))); goto fail; } } @@ -583,22 +627,23 @@ ah6_input(mp, offp, proto) */ cksum = malloc(siz1, M_TEMP, M_NOWAIT); if (!cksum) { - printf("IPv6 AH input: couldn't alloc temporary region for cksum\n"); + ipseclog((LOG_DEBUG, "IPv6 AH input: " + "couldn't alloc temporary region for cksum\n")); ipsec6stat.in_inval++; goto fail; } - if (ah6_calccksum(m, (caddr_t)cksum, algo, sa)) { + if (ah6_calccksum(m, (caddr_t)cksum, algo, sav)) { free(cksum, M_TEMP); ipsec6stat.in_inval++; goto fail; } - ipsec6stat.in_ahhist[sa->alg_auth]++; + ipsec6stat.in_ahhist[sav->alg_auth]++; { caddr_t sumpos = NULL; - if (sa->flags & SADB_X_EXT_OLD) { + if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ sumpos = (caddr_t)(ah + 1); } else { @@ -607,9 +652,9 @@ ah6_input(mp, offp, proto) } if (bcmp(sumpos, cksum, siz) != 0) { - log(LOG_AUTH, "checksum mismatch in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sa)); + ipseclog((LOG_WARNING, + "checksum mismatch in IPv6 AH input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); free(cksum, M_TEMP); ipsec6stat.in_ahauthfail++; goto fail; @@ -630,7 +675,7 @@ ah6_input(mp, offp, proto) struct ip6_hdr *nip6; size_t sizoff; - sizoff = (sa->flags & SADB_X_EXT_OLD) ? 0 : 4; + sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1 + sizeof(struct ip6_hdr), IPPROTO_DONE); @@ -653,27 +698,30 @@ ah6_input(mp, offp, proto) if (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) { #if 0 - printf("IPv6 AH input: authentication succeess\n"); -#else - ; + ipseclog((LOG_DEBUG, + "IPv6 AH input: authentication succeess\n")); #endif ipsec6stat.in_ahauthsucc++; } else { - log(LOG_AUTH, "authentication failed in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sa)); + ipseclog((LOG_WARNING, + "authentication failed in IPv6 AH input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); ipsec6stat.in_ahauthfail++; + goto fail; } /* * update sequence number. */ - if ((sa->flags & SADB_X_EXT_OLD) == 0 && sa->replay) { - (void)ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sa); + if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { + if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { + ipsec6stat.in_ahreplay++; + goto fail; + } } /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec6_tunnel_validate(ip6, nxt, sa) && nxt == IPPROTO_IPV6) { + if (ipsec6_tunnel_validate(ip6, nxt, sav) && nxt == IPPROTO_IPV6) { /* * strip off all the headers that precedes AH. * IP6 xx AH IP6' payload -> IP6' payload @@ -685,7 +733,7 @@ ah6_input(mp, offp, proto) u_int32_t flowinfo; /*net endian*/ flowinfo = ip6->ip6_flow; - if (sa->flags & SADB_X_EXT_OLD) { + if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ stripsiz = sizeof(struct ah) + siz1; } else { @@ -707,11 +755,12 @@ ah6_input(mp, offp, proto) ip6 = mtod(m, struct ip6_hdr *); /* ECN consideration. */ ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow); - if (!key_checktunnelsanity(sa, AF_INET6, + if (!key_checktunnelsanity(sav, AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { - log(LOG_NOTICE, "ipsec tunnel address mismatch in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sa)); + ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " + "in IPv6 AH input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav))); ipsec6stat.in_inval++; goto fail; } @@ -733,7 +782,7 @@ ah6_input(mp, offp, proto) m->m_flags &= ~M_AUTHIPDGM; #endif - key_sa_recordxfer(sa, m); + key_sa_recordxfer(sav, m); s = splimp(); if (IF_QFULL(&ip6intrq)) { @@ -752,6 +801,7 @@ ah6_input(mp, offp, proto) * the packet is placed in a single mbuf. */ size_t stripsiz = 0; +#ifndef PULLDOWN_TEST char *prvnxtp; /* @@ -761,8 +811,9 @@ ah6_input(mp, offp, proto) */ prvnxtp = ip6_get_prevhdr(m, off); /* XXX */ *prvnxtp = nxt; +#endif - if (sa->flags & SADB_X_EXT_OLD) { + if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ stripsiz = sizeof(struct ah) + siz1; } else { @@ -770,6 +821,7 @@ ah6_input(mp, offp, proto) stripsiz = sizeof(struct newah) + siz1; } +#ifndef PULLDOWN_TEST ip6 = mtod(m, struct ip6_hdr *); ovbcopy((caddr_t)ip6, (caddr_t)(((u_char *)ip6) + stripsiz), off); @@ -779,26 +831,29 @@ ah6_input(mp, offp, proto) ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); +#else + off += stripsiz; +#endif - key_sa_recordxfer(sa, m); + key_sa_recordxfer(sav, m); } *offp = off; *mp = m; - if (sa) { + if (sav) { KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah6_input call free SA:%p\n", sa)); - key_freesa(sa); + printf("DP ah6_input call free SA:%p\n", sav)); + key_freesav(sav); } ipsec6stat.in_success++; return nxt; fail: - if (sa) { + if (sav) { KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah6_input call free SA:%p\n", sa)); - key_freesa(sa); + printf("DP ah6_input call free SA:%p\n", sav)); + key_freesav(sav); } if (m) m_freem(m); diff --git a/sys/netinet6/ah_output.c b/sys/netinet6/ah_output.c index 30e9dc2ad3ca..3737bda3549e 100644 --- a/sys/netinet6/ah_output.c +++ b/sys/netinet6/ah_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: ah_output.c,v 1.5 2000/01/06 07:31:11 itojun Exp $ */ +/* $NetBSD: ah_output.c,v 1.6 2000/01/31 14:19:02 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -35,8 +35,6 @@ #include "opt_inet.h" -#define ahdprintf(x) printf x - #include #include #include @@ -58,11 +56,9 @@ #include #include #include -#include #ifdef INET6 #include -#include #include #include #endif @@ -73,6 +69,8 @@ #include #include +#include + static struct in_addr *ah4_finaldst __P((struct mbuf *)); /* @@ -91,19 +89,19 @@ ah_hdrsiz(isr) if (isr == NULL) panic("ah_hdrsiz: NULL was passed.\n"); - if (isr->proto != IPPROTO_AH) + if (isr->saidx.proto != IPPROTO_AH) panic("unsupported mode passed to ah_hdrsiz"); - if (isr->sa == NULL) - goto contrive; - if (isr->sa->state != SADB_SASTATE_MATURE - && isr->sa->state != SADB_SASTATE_DYING) - goto contrive; + if (isr->sav == NULL) + goto estimate; + if (isr->sav->state != SADB_SASTATE_MATURE + && isr->sav->state != SADB_SASTATE_DYING) + goto estimate; /* we need transport mode AH. */ - algo = &ah_algorithms[isr->sa->alg_auth]; + algo = &ah_algorithms[isr->sav->alg_auth]; if (!algo) - goto contrive; + goto estimate; /* * XXX @@ -112,15 +110,15 @@ ah_hdrsiz(isr) * * XXX variable size padding support */ - hdrsiz = (((*algo->sumsiz)(isr->sa) + 3) & ~(4 - 1)); - if (isr->sa->flags & SADB_X_EXT_OLD) + hdrsiz = (((*algo->sumsiz)(isr->sav) + 3) & ~(4 - 1)); + if (isr->sav->flags & SADB_X_EXT_OLD) hdrsiz += sizeof(struct ah); else hdrsiz += sizeof(struct newah); return hdrsiz; - contrive: + estimate: /* ASSUMING: * sizeof(struct newah) > sizeof(struct ah). * 16 = (16 + 3) & ~(4 - 1). @@ -140,7 +138,7 @@ ah4_output(m, isr) struct mbuf *m; struct ipsecrequest *isr; { - struct secas *sa = isr->sa; + struct secasvar *sav = isr->sav; struct ah_algorithm *algo; u_int32_t spi; u_char *ahdrpos; @@ -154,34 +152,33 @@ ah4_output(m, isr) int error; /* sanity checks */ - if ((sa->flags & SADB_X_EXT_OLD) == 0 && !sa->replay) { + if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) { struct ip *ip; ip = mtod(m, struct ip *); - printf("ah4_output: internal error: " - "sa->replay is null: " - "%x->%x, SPI=%u\n", + ipseclog((LOG_DEBUG, "ah4_output: internal error: " + "sav->replay is null: %x->%x, SPI=%u\n", (u_int32_t)ntohl(ip->ip_src.s_addr), (u_int32_t)ntohl(ip->ip_dst.s_addr), - (u_int32_t)ntohl(sa->spi)); + (u_int32_t)ntohl(sav->spi))); ipsecstat.out_inval++; m_freem(m); return EINVAL; } - algo = &ah_algorithms[sa->alg_auth]; - spi = sa->spi; + algo = &ah_algorithms[sav->alg_auth]; + spi = sav->spi; /* * determine the size to grow. */ - if (sa->flags & SADB_X_EXT_OLD) { + if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ - plen = ((*algo->sumsiz)(sa) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ + plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ ahlen = plen + sizeof(struct ah); } else { /* RFC 2402 */ - plen = ((*algo->sumsiz)(sa) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ + plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ ahlen = plen + sizeof(struct newah); } @@ -201,7 +198,8 @@ ah4_output(m, isr) struct mbuf *n; MGET(n, M_DONTWAIT, MT_DATA); if (!n) { - printf("ENOBUFS in ah4_output %d\n", __LINE__); + ipseclog((LOG_DEBUG, "ENOBUFS in ah4_output %d\n", + __LINE__)); m_freem(m); return ENOBUFS; } @@ -222,7 +220,7 @@ ah4_output(m, isr) /* * initialize AH. */ - if (sa->flags & SADB_X_EXT_OLD) { + if (sav->flags & SADB_X_EXT_OLD) { struct ah *ahdr; ahdr = (struct ah *)ahdrpos; @@ -241,12 +239,23 @@ ah4_output(m, isr) ahdr->ah_nxt = ip->ip_p; ahdr->ah_reserve = htons(0); ahdr->ah_spi = spi; - sa->replay->count++; + if (sav->replay->count == ~0) { + if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) { + /* XXX Is it noisy ? */ + ipseclog((LOG_WARNING, + "replay counter overflowed. %s\n", + ipsec_logsastr(sav))); + ipsecstat.out_inval++; + m_freem(m); + return EINVAL; + } + } + sav->replay->count++; /* * XXX sequence number must not be cycled, if the SA is * installed by IKE daemon. */ - ahdr->ah_seq = htonl(sa->replay->count); + ahdr->ah_seq = htonl(sav->replay->count); bzero(ahdr + 1, plen); } @@ -257,7 +266,7 @@ ah4_output(m, isr) if (ahlen < (IP_MAXPACKET - ntohs(ip->ip_len))) ip->ip_len = htons(ntohs(ip->ip_len) + ahlen); else { - printf("IPv4 AH output: size exceeds limit\n"); + ipseclog((LOG_ERR, "IPv4 AH output: size exceeds limit\n")); ipsecstat.out_inval++; m_freem(m); return EMSGSIZE; @@ -280,9 +289,10 @@ ah4_output(m, isr) * calcurate the checksum, based on security association * and the algorithm specified. */ - error = ah4_calccksum(m, (caddr_t)ahsumpos, algo, sa); + error = ah4_calccksum(m, (caddr_t)ahsumpos, algo, sav); if (error) { - printf("error after ah4_calccksum, called from ah4_output"); + ipseclog((LOG_ERR, + "error after ah4_calccksum, called from ah4_output")); m = NULL; ipsecstat.out_inval++; return error; @@ -293,28 +303,28 @@ ah4_output(m, isr) ip->ip_dst.s_addr = dst.s_addr; } ipsecstat.out_success++; - ipsecstat.out_ahhist[sa->alg_auth]++; - key_sa_recordxfer(sa, m); + ipsecstat.out_ahhist[sav->alg_auth]++; + key_sa_recordxfer(sav, m); return 0; } /* Calculate AH length */ int -ah_hdrlen(sa) - struct secas *sa; +ah_hdrlen(sav) + struct secasvar *sav; { struct ah_algorithm *algo; int plen, ahlen; - algo = &ah_algorithms[sa->alg_auth]; - if (sa->flags & SADB_X_EXT_OLD) { + algo = &ah_algorithms[sav->alg_auth]; + if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ - plen = ((*algo->sumsiz)(sa) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ + plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ ahlen = plen + sizeof(struct ah); } else { /* RFC 2402 */ - plen = ((*algo->sumsiz)(sa) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ + plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ ahlen = plen + sizeof(struct newah); } @@ -334,7 +344,7 @@ ah6_output(m, nexthdrp, md, isr) { struct mbuf *mprev; struct mbuf *mah; - struct secas *sa = isr->sa; + struct secasvar *sav = isr->sav; struct ah_algorithm *algo; u_int32_t spi; u_char *ahsumpos = NULL; @@ -344,19 +354,19 @@ ah6_output(m, nexthdrp, md, isr) struct ip6_hdr *ip6; if (m->m_len < sizeof(struct ip6_hdr)) { - printf("ah6_output: first mbuf too short\n"); + ipseclog((LOG_DEBUG, "ah6_output: first mbuf too short\n")); m_freem(m); return EINVAL; } - ahlen = ah_hdrlen(sa); + ahlen = ah_hdrlen(sav); if (ahlen == 0) return 0; for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) ; if (!mprev || mprev->m_next != md) { - printf("ah6_output: md is not in chain\n"); + ipseclog((LOG_DEBUG, "ah6_output: md is not in chain\n")); m_freem(m); return EINVAL; } @@ -381,28 +391,29 @@ ah6_output(m, nexthdrp, md, isr) /* fix plen */ if (m->m_pkthdr.len - sizeof(struct ip6_hdr) > IPV6_MAXPACKET) { - printf("ip6_output: AH with IPv6 jumbogram is not supported\n"); + ipseclog((LOG_ERR, + "ip6_output: AH with IPv6 jumbogram is not supported\n")); m_freem(m); return EINVAL; } ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); - if ((sa->flags & SADB_X_EXT_OLD) == 0 && !sa->replay) { - printf("ah6_output: internal error: " - "sa->replay is null: SPI=%u\n", - (u_int32_t)ntohl(sa->spi)); + if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) { + ipseclog((LOG_DEBUG, "ah6_output: internal error: " + "sav->replay is null: SPI=%u\n", + (u_int32_t)ntohl(sav->spi))); ipsec6stat.out_inval++; return 0; /* no change at all */ } - algo = &ah_algorithms[sa->alg_auth]; - spi = sa->spi; + algo = &ah_algorithms[sav->alg_auth]; + spi = sav->spi; /* * initialize AH. */ - if (sa->flags & SADB_X_EXT_OLD) { + if (sav->flags & SADB_X_EXT_OLD) { struct ah *ahdr = mtod(mah, struct ah *); plen = mah->m_len - sizeof(struct ah); @@ -423,12 +434,23 @@ ah6_output(m, nexthdrp, md, isr) ahdr->ah_len = (plen >> 2) + 1; /* plus one for seq# */ ahdr->ah_reserve = htons(0); ahdr->ah_spi = spi; - sa->replay->count++; + if (sav->replay->count == ~0) { + if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) { + /* XXX Is it noisy ? */ + ipseclog((LOG_WARNING, + "replay counter overflowed. %s\n", + ipsec_logsastr(sav))); + ipsecstat.out_inval++; + m_freem(m); + return EINVAL; + } + } + sav->replay->count++; /* * XXX sequence number must not be cycled, if the SA is * installed by IKE daemon. */ - ahdr->ah_seq = htonl(sa->replay->count); + ahdr->ah_seq = htonl(sav->replay->count); bzero(ahdr + 1, plen); } @@ -436,13 +458,13 @@ ah6_output(m, nexthdrp, md, isr) * calcurate the checksum, based on security association * and the algorithm specified. */ - error = ah6_calccksum(m, (caddr_t)ahsumpos, algo, sa); + error = ah6_calccksum(m, (caddr_t)ahsumpos, algo, sav); if (error) ipsec6stat.out_inval++; else ipsec6stat.out_success++; - ipsec6stat.out_ahhist[sa->alg_auth]++; - key_sa_recordxfer(sa, m); + ipsec6stat.out_ahhist[sav->alg_auth]++; + key_sa_recordxfer(sav, m); return(error); } @@ -472,7 +494,8 @@ ah4_finaldst(m) hlen = (ip->ip_hl << 2); if (m->m_len < hlen) { - printf("ah4_finaldst: parameter mbuf wrong (not pulled up)\n"); + ipseclog((LOG_DEBUG, + "ah4_finaldst: parameter mbuf wrong (not pulled up)\n")); return NULL; } @@ -481,7 +504,8 @@ ah4_finaldst(m) optlen = hlen - sizeof(struct ip); if (optlen < 0) { - printf("ah4_finaldst: wrong optlen %d\n", optlen); + ipseclog((LOG_DEBUG, "ah4_finaldst: wrong optlen %d\n", + optlen)); return NULL; } @@ -499,9 +523,10 @@ ah4_finaldst(m) case IPOPT_SSRR: if (q[i + IPOPT_OLEN] <= 0 || optlen - i < q[i + IPOPT_OLEN]) { - printf("ip_finaldst: invalid IP option " - "(code=%02x len=%02x)\n", - q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]); + ipseclog((LOG_ERR, + "ip_finaldst: invalid IP option " + "(code=%02x len=%02x)\n", + q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN])); return NULL; } i += q[i + IPOPT_OLEN] - sizeof(struct in_addr); @@ -509,9 +534,10 @@ ah4_finaldst(m) default: if (q[i + IPOPT_OLEN] <= 0 || optlen - i < q[i + IPOPT_OLEN]) { - printf("ip_finaldst: invalid IP option " - "(code=%02x len=%02x)\n", - q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]); + ipseclog((LOG_ERR, + "ip_finaldst: invalid IP option " + "(code=%02x len=%02x)\n", + q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN])); return NULL; } i += q[i + IPOPT_OLEN]; diff --git a/sys/netinet6/esp.h b/sys/netinet6/esp.h index 83bb4a2a3efd..4f0c92d1540c 100644 --- a/sys/netinet6/esp.h +++ b/sys/netinet6/esp.h @@ -1,4 +1,4 @@ -/* $NetBSD: esp.h,v 1.6 2000/01/06 07:31:11 itojun Exp $ */ +/* $NetBSD: esp.h,v 1.7 2000/01/31 14:19:02 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -71,28 +71,27 @@ struct esptail { }; struct esp_algorithm_state { - struct secas *sa; + struct secasvar *sav; void* foo; /*per algorithm data - maybe*/ }; /* XXX yet to be defined */ struct esp_algorithm { size_t padbound; /* pad boundary, in byte */ - int (*mature) __P((struct secas *)); + int (*mature) __P((struct secasvar *)); int keymin; /* in bits */ int keymax; /* in bits */ - int (*ivlen) __P((struct secas *)); + int (*ivlen) __P((struct secasvar *)); int (*decrypt) __P((struct mbuf *, size_t, - struct secas *, struct esp_algorithm *, int)); + struct secasvar *, struct esp_algorithm *, int)); int (*encrypt) __P((struct mbuf *, size_t, size_t, - struct secas *, struct esp_algorithm *, int)); + struct secasvar *, struct esp_algorithm *, int)); }; #ifdef _KERNEL extern struct esp_algorithm esp_algorithms[]; /* crypt routines */ -struct secasb; extern int esp4_output __P((struct mbuf *, struct ipsecrequest *)); extern void esp4_input __P((struct mbuf *, ...)); extern size_t esp_hdrsiz __P((struct ipsecrequest *)); @@ -104,8 +103,8 @@ extern int esp6_input __P((struct mbuf **, int *, int)); #endif /* INET6 */ #endif /*_KERNEL*/ -struct secas; +struct secasvar; extern int esp_auth __P((struct mbuf *, size_t, size_t, - struct secas *, u_char *)); + struct secasvar *, u_char *)); #endif /*_NETINET6_ESP_H_*/ diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 04c408133e43..3644dd2aa7ad 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,4 @@ -/* $NetBSD: in6_pcb.c,v 1.13 2000/01/26 17:06:36 itojun Exp $ */ +/* $NetBSD: in6_pcb.c,v 1.14 2000/01/31 14:19:02 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -731,8 +731,6 @@ in6_pcbdetach(in6p) struct socket *so = in6p->in6p_socket; #ifdef IPSEC - if (sotoin6pcb(so) != 0) - key_freeso(so); ipsec6_delete_pcbpolicy(in6p); #endif /* IPSEC */ sotoin6pcb(so) = 0; diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h index 72749ed5e84e..eea0b71b4bb9 100644 --- a/sys/netinet6/in6_pcb.h +++ b/sys/netinet6/in6_pcb.h @@ -1,4 +1,4 @@ -/* $NetBSD: in6_pcb.h,v 1.7 1999/12/27 06:38:47 itojun Exp $ */ +/* $NetBSD: in6_pcb.h,v 1.8 2000/01/31 14:19:03 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -77,6 +77,7 @@ * control block. */ struct icmp6_filter; +struct inpcbpolicy; struct in6pcb { struct in6pcb *in6p_next, *in6p_prev; @@ -102,9 +103,7 @@ struct in6pcb { LIST_ENTRY(in6pcb) in6p_hlist; /* hash chain */ u_long in6p_hash; /* hash value */ #if 1 /*IPSEC*/ - struct secpolicy *in6p_sp; /* security policy. It may not be - * used according to policy selection. - */ + struct inpcbpolicy *in6p_sp; /* security policy. */ #endif struct icmp6_filter *in6p_icmp6filt; int in6p_cksum; /* IPV6_CHECKSUM setsockopt */ diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 55ed8e6cce68..8a8b736d72e8 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_forward.c,v 1.6 2000/01/06 15:46:09 itojun Exp $ */ +/* $NetBSD: ip6_forward.c,v 1.7 2000/01/31 14:19:03 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -327,8 +328,37 @@ ip6_forward(m, srcrt) in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig); if (mcopy) { u_long mtu; +#ifdef IPSEC_IPV6FWD + struct secpolicy *sp; + int ipsecerror; + size_t ipsechdrsiz; +#endif mtu = rt->rt_ifp->if_mtu; +#ifdef IPSEC_IPV6FWD + /* + * When we do IPsec tunnel ingress, we need to play + * with if_mtu value (decrement IPsec header size + * from mtu value). The code is much simpler than v4 + * case, as we have the outgoing interface for + * encapsulated packet as "rt->rt_ifp". + */ + sp = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND, + IP_FORWARDING, &ipsecerror); + if (sp) { + ipsechdrsiz = ipsec6_hdrsiz(mcopy, + IPSEC_DIR_OUTBOUND, NULL); + if (ipsechdrsiz < mtu) + mtu -= ipsechdrsiz; + } + + /* + * if mtu becomes less than minimum MTU, + * tell minimum MTU (and I'll need to fragment it). + */ + if (mtu < IPV6_MMTU) + mtu = IPV6_MMTU; +#endif icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu); } m_freem(m); diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index fc46a0a84d91..11b46628fad5 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_output.c,v 1.12 2000/01/26 17:06:37 itojun Exp $ */ +/* $NetBSD: ip6_output.c,v 1.13 2000/01/31 14:19:03 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -191,9 +191,9 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) #ifdef IPSEC /* get a security policy for this packet */ if (so == NULL) - sp = ipsec6_getpolicybyaddr(m, 0, &error); + sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); else - sp = ipsec6_getpolicybysock(m, so, &error); + sp = ipsec6_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); if (sp == NULL) { ipsec6stat.out_inval++; @@ -1295,19 +1295,19 @@ ip6_ctloutput(op, so, level, optname, mp) case IPV6_IPSEC_POLICY: { caddr_t req = NULL; - int len = 0; + size_t len = 0; + int priv = 0; if (p == 0 || suser(p->p_ucred, &p->p_acflag)) priv = 0; else priv = 1; - if (m != 0) { + if (m) { req = mtod(m, caddr_t); len = m->m_len; } - error = ipsec_set_policy(&in6p->in6p_sp, - optname, req, len, - priv); + error = ipsec6_set_policy(in6p, + optname, req, len, priv); } break; #endif /* IPSEC */ @@ -1452,8 +1452,17 @@ ip6_ctloutput(op, so, level, optname, mp) #ifdef IPSEC case IPV6_IPSEC_POLICY: - error = ipsec_get_policy(in6p->in6p_sp, mp); + { + caddr_t req = NULL; + size_t len = 0; + + if (m) { + req = mtod(m, caddr_t); + len = m->m_len; + } + error = ipsec6_get_policy(in6p, req, len, mp); break; + } #endif /* IPSEC */ default: diff --git a/sys/netinet6/ipcomp_core.c b/sys/netinet6/ipcomp_core.c index 84acb409aa37..8e86accc8051 100644 --- a/sys/netinet6/ipcomp_core.c +++ b/sys/netinet6/ipcomp_core.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipcomp_core.c,v 1.8 2000/01/26 17:08:41 itojun Exp $ */ +/* $NetBSD: ipcomp_core.c,v 1.9 2000/01/31 14:19:04 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,7 @@ #include #include +#include #include @@ -83,10 +85,6 @@ struct ipcomp_algorithm ipcomp_algorithms[] = { { NULL, NULL, 90 }, }; -#ifdef __NetBSD__ -#define ovbcopy bcopy -#endif - static void * deflate_alloc(aux, items, siz) void *aux; @@ -238,18 +236,18 @@ deflate_common(m, md, lenp, mode) } else if (zerror == Z_STREAM_END) break; else { - printf("ipcomp_%scompress: %sflate: %s\n", + ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n", mode ? "de" : "", mode ? "in" : "de", - zs.msg ? zs.msg : "unknown error"); + zs.msg ? zs.msg : "unknown error")); error = EINVAL; goto fail; } } zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs); if (zerror != Z_OK) { - printf("ipcomp_%scompress: %sflate: %s\n", + ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n", mode ? "de" : "", mode ? "in" : "de", - zs.msg ? zs.msg : "unknown error"); + zs.msg ? zs.msg : "unknown error")); error = EINVAL; goto fail; } diff --git a/sys/netinet6/ipcomp_input.c b/sys/netinet6/ipcomp_input.c index 35e9d1788842..1144696d64a3 100644 --- a/sys/netinet6/ipcomp_input.c +++ b/sys/netinet6/ipcomp_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipcomp_input.c,v 1.7 2000/01/06 15:46:10 itojun Exp $ */ +/* $NetBSD: ipcomp_input.c,v 1.8 2000/01/31 14:19:05 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -62,7 +62,6 @@ #ifdef INET6 #include -#include #include #endif #include @@ -74,11 +73,9 @@ #include -#define IPLEN_FLIPPED +#include -#ifdef __NetBSD__ -#define ovbcopy bcopy -#endif +#define IPLEN_FLIPPED #ifdef INET extern struct protosw inetsw[]; @@ -101,7 +98,7 @@ ipcomp4_input(m, va_alist) size_t hlen; int error; size_t newlen, olen; - struct secas *sa = NULL; + struct secasvar *sav = NULL; int off, proto; va_list ap; @@ -112,23 +109,27 @@ ipcomp4_input(m, va_alist) if (off + sizeof(struct ipcomp) > MHLEN) { /*XXX the restriction should be relaxed*/ - printf("IPv4 IPComp input: assumption failed (header too long)\n"); + ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " + "(header too long)\n")); + ipsecstat.in_inval++; goto fail; } if (m->m_len < off + sizeof(struct ipcomp)) { m = m_pullup(m, off + sizeof(struct ipcomp)); if (!m) { - printf("IPv4 IPComp input: can't pullup;" - "dropping the packet for simplicity\n"); - ipsecstat.in_inval++; + ipseclog((LOG_DEBUG, "IPv4 IPComp input: can't pullup;" + "dropping the packet for simplicity\n")); + ipsecstat.in_nomem++; goto fail; } } else if (m->m_len > off + sizeof(struct ipcomp)) { /* chop header part from the packet header chain */ struct mbuf *n; MGETHDR(n, M_DONTWAIT, MT_HEADER); - if (!n) + if (!n) { + ipsecstat.in_nomem++; goto fail; + } M_COPY_PKTHDR(n, m); MH_ALIGN(n, off + sizeof(struct ipcomp)); n->m_len = off + sizeof(struct ipcomp); @@ -152,12 +153,12 @@ ipcomp4_input(m, va_alist) cpi = ntohs(ipcomp->comp_cpi); if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) { - sa = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, + sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, IPPROTO_IPCOMP, htonl(cpi)); - if (sa != NULL - && (sa->state == SADB_SASTATE_MATURE - || sa->state == SADB_SASTATE_DYING)) { - cpi = sa->alg_enc; /*XXX*/ + if (sav != NULL + && (sav->state == SADB_SASTATE_MATURE + || sav->state == SADB_SASTATE_DYING)) { + cpi = sav->alg_enc; /*XXX*/ /* other parameters to look at? */ } } @@ -166,8 +167,8 @@ ipcomp4_input(m, va_alist) else algo = NULL; if (!algo) { - printf("IPv4 IPComp input: unknown cpi %u; " - "dropping the packet for simplicity\n", cpi); + ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n", + cpi)); ipsecstat.in_nosa++; goto fail; } @@ -186,9 +187,14 @@ ipcomp4_input(m, va_alist) newlen = m->m_pkthdr.len - off; error = (*algo->decompress)(m, m->m_next, &newlen); if (error != 0) { + if (error == EINVAL) + ipsecstat.in_inval++; + else if (error == ENOBUFS) + ipsecstat.in_nomem++; m = NULL; goto fail; } + ipsecstat.in_comphist[cpi]++; /* * returning decompressed packet onto icmp is meaningless. @@ -224,10 +230,10 @@ ipcomp4_input(m, va_alist) ip->ip_p = nxt; } - if (sa) { - key_sa_recordxfer(sa, m); - key_freesa(sa); - sa = NULL; + if (sav) { + key_sa_recordxfer(sav, m); + key_freesav(sav); + sav = NULL; } if (nxt != IPPROTO_DONE) @@ -240,8 +246,8 @@ ipcomp4_input(m, va_alist) return; fail: - if (sa) - key_freesa(sa); + if (sav) + key_freesav(sav); if (m) m_freem(m); return; @@ -264,7 +270,7 @@ ipcomp6_input(mp, offp, proto) u_int16_t nxt; int error; size_t newlen; - struct secas *sa = NULL; + struct secasvar *sav = NULL; m = *mp; off = *offp; @@ -286,11 +292,13 @@ ipcomp6_input(mp, offp, proto) break; } if (!n) { - printf("IPv6 IPComp input: wrong mbuf chain\n"); + ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n")); + ipsecstat.in_inval++; goto fail; } if (n->m_len < skip + sizeof(struct ipcomp)) { - printf("IPv6 IPComp input: wrong mbuf chain\n"); + ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n")); + ipsecstat.in_inval++; goto fail; } ip6 = mtod(m, struct ip6_hdr *); @@ -300,8 +308,10 @@ ipcomp6_input(mp, offp, proto) /* split mbuf to ease the following steps*/ l = n->m_len - (skip + sizeof(struct ipcomp)); p = m_copym(n, skip + sizeof(struct ipcomp), l , M_DONTWAIT); - if (!p) + if (!p) { + ipsecstat.in_nomem++; goto fail; + } for (q = p; q && q->m_next; q = q->m_next) ; q->m_next = n->m_next; @@ -316,12 +326,12 @@ ipcomp6_input(mp, offp, proto) cpi = ntohs(ipcomp->comp_cpi); if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) { - sa = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, + sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, IPPROTO_IPCOMP, htonl(cpi)); - if (sa != NULL - && (sa->state == SADB_SASTATE_MATURE - || sa->state == SADB_SASTATE_DYING)) { - cpi = sa->alg_enc; /*XXX*/ + if (sav != NULL + && (sav->state == SADB_SASTATE_MATURE + || sav->state == SADB_SASTATE_DYING)) { + cpi = sav->alg_enc; /*XXX*/ /* other parameters to look at? */ } } @@ -330,8 +340,8 @@ ipcomp6_input(mp, offp, proto) else algo = NULL; if (!algo) { - printf("IPv6 IPComp input: unknown cpi %u; " - "dropping the packet for simplicity\n", cpi); + ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; " + "dropping the packet for simplicity\n", cpi)); ipsec6stat.in_nosa++; goto fail; } @@ -339,9 +349,14 @@ ipcomp6_input(mp, offp, proto) newlen = m->m_pkthdr.len - off - sizeof(struct ipcomp); error = (*algo->decompress)(m, md, &newlen); if (error != 0) { + if (error == EINVAL) + ipsec6stat.in_inval++; + else if (error == ENOBUFS) + ipsec6stat.in_nomem++; m = NULL; goto fail; } + ipsec6stat.in_comphist[cpi]++; m->m_pkthdr.len = off + sizeof(struct ipcomp) + newlen; /* @@ -367,10 +382,10 @@ ipcomp6_input(mp, offp, proto) ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); } - if (sa) { - key_sa_recordxfer(sa, m); - key_freesa(sa); - sa = NULL; + if (sav) { + key_sa_recordxfer(sav, m); + key_freesav(sav); + sav = NULL; } *offp = off; *mp = m; @@ -380,8 +395,8 @@ ipcomp6_input(mp, offp, proto) fail: if (m) m_freem(m); - if (sa) - key_freesa(sa); + if (sav) + key_freesav(sav); return IPPROTO_DONE; } #endif /* INET6 */ diff --git a/sys/netinet6/ipcomp_output.c b/sys/netinet6/ipcomp_output.c index 545ee93f0e63..aeddbfbe3dab 100644 --- a/sys/netinet6/ipcomp_output.c +++ b/sys/netinet6/ipcomp_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipcomp_output.c,v 1.7 2000/01/06 15:46:10 itojun Exp $ */ +/* $NetBSD: ipcomp_output.c,v 1.8 2000/01/31 14:19:05 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -62,7 +62,6 @@ #ifdef INET6 #include -#include #include #endif #include @@ -74,9 +73,7 @@ #include -#ifdef __NetBSD__ -#define ovbcopy bcopy -#endif +#include static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *, struct ipsecrequest *, int)); @@ -111,7 +108,7 @@ ipcomp_output(m, nexthdrp, md, isr, af) struct mbuf *md0; struct mbuf *mprev; struct ipcomp *ipcomp; - struct secas *sa = isr->sa; + struct secasvar *sav = isr->sav; struct ipcomp_algorithm *algo; u_int16_t cpi; /* host order */ size_t plen0, plen; /*payload length to be compressed*/ @@ -131,22 +128,22 @@ ipcomp_output(m, nexthdrp, md, isr, af) break; #endif default: - printf("ipcomp_output: unsupported af %d\n", af); + ipseclog((LOG_ERR, "ipcomp_output: unsupported af %d\n", af)); return 0; /* no change at all */ } /* grab parameters */ - if ((ntohl(sa->spi) & ~0xffff) != 0 || sa->alg_enc >= IPCOMP_MAX - || ipcomp_algorithms[sa->alg_enc].compress == NULL) { + if ((ntohl(sav->spi) & ~0xffff) != 0 || sav->alg_enc >= IPCOMP_MAX + || ipcomp_algorithms[sav->alg_enc].compress == NULL) { ipsecstat.out_inval++; m_freem(m); return EINVAL; } - if ((sa->flags & SADB_X_EXT_RAWCPI) == 0) - cpi = sa->alg_enc; + if ((sav->flags & SADB_X_EXT_RAWCPI) == 0) + cpi = sav->alg_enc; else - cpi = ntohl(sa->spi) & 0xffff; - algo = &ipcomp_algorithms[sa->alg_enc]; /*XXX*/ + cpi = ntohl(sav->spi) & 0xffff; + algo = &ipcomp_algorithms[sav->alg_enc]; /*XXX*/ /* compute original payload length */ plen = 0; @@ -172,7 +169,20 @@ ipcomp_output(m, nexthdrp, md, isr, af) for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) ; if (mprev == NULL || mprev->m_next != md) { - printf("ipcomp%d_output: md is not in chain\n", afnumber); + ipseclog((LOG_DEBUG, "ipcomp%d_output: md is not in chain\n", + afnumber)); + switch (af) { +#ifdef INET + case AF_INET: + ipsecstat.out_inval++; + break; +#endif +#ifdef INET6 + case AF_INET6: + ipsec6stat.out_inval++; + break; +#endif + } m_freem(m); m_freem(md0); return EINVAL; @@ -188,7 +198,7 @@ ipcomp_output(m, nexthdrp, md, isr, af) /* compress data part */ if ((*algo->compress)(m, md, &plen) || mprev->m_next == NULL) { - printf("packet compression failure\n"); + ipseclog((LOG_ERR, "packet compression failure\n")); m = NULL; m_freem(md0); switch (af) { @@ -206,6 +216,18 @@ ipcomp_output(m, nexthdrp, md, isr, af) error = EINVAL; goto fail; } + switch (af) { +#ifdef INET + case AF_INET: + ipsecstat.out_comphist[sav->alg_enc]++; + break; +#endif +#ifdef INET6 + case AF_INET6: + ipsec6stat.out_comphist[sav->alg_enc]++; + break; +#endif + } md = mprev->m_next; /* @@ -292,7 +314,8 @@ ipcomp_output(m, nexthdrp, md, isr, af) if (compoff + complen + plen < IP_MAXPACKET) ip->ip_len = htons(compoff + complen + plen); else { - printf("IPv4 ESP output: size exceeds limit\n"); + ipseclog((LOG_ERR, + "IPv4 ESP output: size exceeds limit\n")); ipsecstat.out_inval++; m_freem(m); error = EMSGSIZE; @@ -309,8 +332,21 @@ ipcomp_output(m, nexthdrp, md, isr, af) } if (!m) { - printf("NULL mbuf after compression in ipcomp%d_output", - afnumber); + ipseclog((LOG_DEBUG, + "NULL mbuf after compression in ipcomp%d_output", + afnumber)); + switch (af) { +#ifdef INET + case AF_INET: + ipsecstat.out_inval++; + break; +#endif +#ifdef INET6 + case AF_INET6: + ipsec6stat.out_inval++; + break; +#endif + } } else { switch (af) { #ifdef INET @@ -329,17 +365,17 @@ ipcomp_output(m, nexthdrp, md, isr, af) switch (af) { #ifdef INET case AF_INET: - ipsecstat.out_esphist[sa->alg_enc]++; + ipsecstat.out_esphist[sav->alg_enc]++; break; #endif #ifdef INET6 case AF_INET6: - ipsec6stat.out_esphist[sa->alg_enc]++; + ipsec6stat.out_esphist[sav->alg_enc]++; break; #endif } #endif - key_sa_recordxfer(sa, m); + key_sa_recordxfer(sav, m); return 0; fail: @@ -358,7 +394,8 @@ ipcomp4_output(m, isr) { struct ip *ip; if (m->m_len < sizeof(struct ip)) { - printf("ipcomp4_output: first mbuf too short\n"); + ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n")); + ipsecstat.out_inval++; m_freem(m); return NULL; } @@ -377,7 +414,8 @@ ipcomp6_output(m, nexthdrp, md, isr) struct ipsecrequest *isr; { if (m->m_len < sizeof(struct ip6_hdr)) { - printf("ipcomp6_output: first mbuf too short\n"); + ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n")); + ipsec6stat.out_inval++; m_freem(m); return NULL; } diff --git a/sys/netinet6/ipsec.c b/sys/netinet6/ipsec.c index fc800ac5305e..21941b208838 100644 --- a/sys/netinet6/ipsec.c +++ b/sys/netinet6/ipsec.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec.c,v 1.13 2000/01/16 18:06:04 itojun Exp $ */ +/* $NetBSD: ipsec.c,v 1.14 2000/01/31 14:19:05 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -48,9 +48,9 @@ #include #include #include -#include #include #include +#include #include #include @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include @@ -67,10 +66,13 @@ #ifdef INET6 #include -#include #include +#endif +#include +#ifdef INET6 +#include #include -#endif /*INET6*/ +#endif #include #include @@ -82,10 +84,18 @@ #include #include +#include + #ifdef __NetBSD__ #define ovbcopy bcopy #endif +#ifdef IPSEC_DEBUG +int ipsec_debug = 1; +#else +int ipsec_debug = 0; +#endif + struct ipsecstat ipsecstat; int ip4_inbound_call_ike = 0; int ip4_ah_cleartos = 1; @@ -111,12 +121,21 @@ int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ #endif /* INET6 */ -static int ipsec_setsecidx __P((struct secindex *, u_int, struct mbuf *, int)); -#if 0 -static void ipsec_setsecidx_pcb __P((struct secindex *, u_int, u_int, - void *, u_int, void *, u_int)); -static int ipsec_delete_policy __P((struct secpolicy *)); +static int ipsec_setspidx_mbuf + __P((struct secpolicyindex *, u_int, u_int, struct mbuf *)); +static void ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); +static void ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); +#ifdef INET6 +static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *)); +static void ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb)); +static void ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); #endif +static struct inpcbpolicy *ipsec_newpcbpolicy __P((void)); +static void ipsec_delpcbpolicy __P((struct inpcbpolicy *)); +static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *src)); +static int ipsec_set_policy __P((struct secpolicy **pcb_sp, + int optname, caddr_t request, size_t len, int priv)); +static int ipsec_get_policy __P((struct secpolicy *pcb_sp, struct mbuf **mp)); static void vshiftl __P((unsigned char *, int, int)); static int ipsec_in_reject __P((struct secpolicy *, struct mbuf *)); static size_t ipsec_hdrsiz __P((struct secpolicy *)); @@ -124,29 +143,9 @@ static struct mbuf *ipsec4_splithdr __P((struct mbuf *)); #ifdef INET6 static struct mbuf *ipsec6_splithdr __P((struct mbuf *)); #endif -static int ipsec4_encapsulate __P((struct mbuf *, struct secas *)); +static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *)); #ifdef INET6 -static int ipsec6_encapsulate __P((struct mbuf *, struct secas *)); -#endif - -#if 1 -#define KMALLOC(p, t, n) \ - ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT)) -#define KFREE(p) \ - free((caddr_t)(p), M_SECA); -#else -#define KMALLOC(p, t, n) \ - do { \ - ((p) = (t)malloc((unsigned long)(n), M_SECA, M_NOWAIT));\ - printf("%s %d: %p <- KMALLOC(%s, %d)\n", \ - __FILE__, __LINE__, (p), #t, n); \ - } while (0) - -#define KFREE(p) \ - do { \ - printf("%s %d: %p -> KFREE()\n", __FILE__, __LINE__, (p));\ - free((caddr_t)(p), M_SECA); \ - } while (0) +static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *)); #endif /* @@ -162,33 +161,31 @@ static int ipsec6_encapsulate __P((struct mbuf *, struct secas *)); * NOTE: IPv6 mapped adddress concern is implemented here. */ struct secpolicy * -ipsec4_getpolicybysock(m, so, error) +ipsec4_getpolicybysock(m, dir, so, error) struct mbuf *m; + u_int dir; struct socket *so; int *error; { - struct secpolicy *sp = NULL; /* policy on socket */ + struct inpcbpolicy *pcbsp = NULL; + struct secpolicy *currsp = NULL; /* policy on socket */ struct secpolicy *kernsp = NULL; /* policy on kernel */ - int priv = 0; + /* sanity check */ if (m == NULL || so == NULL || error == NULL) panic("ipsec4_getpolicybysock: NULL pointer was passed.\n"); switch (so->so_proto->pr_domain->dom_family) { case AF_INET: - sp = sotoinpcb(so)->inp_sp; - if (so->so_uid == 0) /*XXX*/ - priv = 1; - else - priv = 0; + /* set spidx in pcb */ + ipsec4_setspidx_inpcb(m, sotoinpcb(so)); + pcbsp = sotoinpcb(so)->inp_sp; break; #ifdef INET6 case AF_INET6: - sp = sotoin6pcb(so)->in6p_sp; - if (so->so_uid == 0) /*XXX*/ - priv = 1; - else - priv = 0; + /* set spidx in pcb */ + ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); + pcbsp = sotoin6pcb(so)->in6p_sp; break; #endif default: @@ -196,30 +193,35 @@ ipsec4_getpolicybysock(m, so, error) } /* sanity check */ - if (sp == NULL) - panic("ipsec4_getpolicybysock: PCB's SP is NULL.\n"); + if (pcbsp == NULL) + panic("ipsec4_getpolicybysock: pcbsp is NULL.\n"); + + switch (dir) { + case IPSEC_DIR_INBOUND: + currsp = pcbsp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + currsp = pcbsp->sp_out; + break; + default: + panic("ipsec4_getpolicybysock: illegal direction.\n"); + } + + /* sanity check */ + if (currsp == NULL) + panic("ipsec4_getpolicybysock: currsp is NULL.\n"); /* when privilieged socket */ - if (priv) { - switch (sp->policy) { + if (pcbsp->priv) { + switch (currsp->policy) { case IPSEC_POLICY_BYPASS: - sp->refcnt++; + currsp->refcnt++; *error = 0; - return sp; + return currsp; case IPSEC_POLICY_ENTRUST: - { - struct secindex idx; - - bzero(&idx, sizeof(idx)); - *error = ipsec_setsecidx(&idx, AF_INET, m, 1); - if (*error != 0) { - *error = ENOBUFS; - return NULL; - } - - kernsp = key_allocsp(&idx); - } + /* look for a policy in SPD */ + kernsp = key_allocsp(&currsp->spidx, dir); /* SP found */ if (kernsp != NULL) { @@ -233,9 +235,9 @@ ipsec4_getpolicybysock(m, so, error) /* no SP found */ if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD && ip4_def_policy.policy != IPSEC_POLICY_NONE) { - printf("fixed system default policy:%d->%d\n", - ip4_def_policy.policy, - IPSEC_POLICY_NONE); + ipseclog((LOG_INFO, + "fixed system default policy: %d->%d\n", + ip4_def_policy.policy, IPSEC_POLICY_NONE)); ip4_def_policy.policy = IPSEC_POLICY_NONE; } ip4_def_policy.refcnt++; @@ -243,15 +245,13 @@ ipsec4_getpolicybysock(m, so, error) return &ip4_def_policy; case IPSEC_POLICY_IPSEC: - sp->refcnt++; - ipsec_setsecidx(&sp->idx, AF_INET, m, 1); + currsp->refcnt++; *error = 0; - return sp; + return currsp; default: - printf("ipsec4_getpolicybysock: " - "Invalid policy for PCB %d\n", - sp->policy); + ipseclog((LOG_ERR, "ipsec4_getpolicybysock: " + "Invalid policy for PCB %d\n", currsp->policy)); *error = EINVAL; return NULL; } @@ -259,16 +259,8 @@ ipsec4_getpolicybysock(m, so, error) } /* when non-privilieged socket */ - { - struct secindex idx; - - /* make a index to look for a policy */ - bzero(&idx, sizeof(idx)); - if ((*error = ipsec_setsecidx(&idx, AF_INET, m, 1)) != 0) - return NULL; - - kernsp = key_allocsp(&idx); - } + /* look for a policy in SPD */ + kernsp = key_allocsp(&currsp->spidx, dir); /* SP found */ if (kernsp != NULL) { @@ -280,20 +272,20 @@ ipsec4_getpolicybysock(m, so, error) } /* no SP found */ - switch (sp->policy) { + switch (currsp->policy) { case IPSEC_POLICY_BYPASS: - printf("ipsec4_getpolicybysock: " + ipseclog((LOG_ERR, "ipsec4_getpolicybysock: " "Illegal policy for non-priviliged defined %d\n", - sp->policy); + currsp->policy)); *error = EINVAL; return NULL; case IPSEC_POLICY_ENTRUST: if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD && ip4_def_policy.policy != IPSEC_POLICY_NONE) { - printf("fixed system default policy:%d->%d\n", - ip4_def_policy.policy, - IPSEC_POLICY_NONE); + ipseclog((LOG_INFO, + "fixed system default policy: %d->%d\n", + ip4_def_policy.policy, IPSEC_POLICY_NONE)); ip4_def_policy.policy = IPSEC_POLICY_NONE; } ip4_def_policy.refcnt++; @@ -301,15 +293,13 @@ ipsec4_getpolicybysock(m, so, error) return &ip4_def_policy; case IPSEC_POLICY_IPSEC: - sp->refcnt++; - ipsec_setsecidx(&sp->idx, AF_INET, m, 1); + currsp->refcnt++; *error = 0; - return sp; + return currsp; default: - printf("ipsec4_policybysock: " - "Invalid policy for PCB %d\n", - sp->policy); + ipseclog((LOG_ERR, "ipsec4_getpolicybysock: " + "Invalid policy for PCB %d\n", currsp->policy)); *error = EINVAL; return NULL; } @@ -327,8 +317,9 @@ ipsec4_getpolicybysock(m, so, error) * others : error occured. */ struct secpolicy * -ipsec4_getpolicybyaddr(m, flag, error) +ipsec4_getpolicybyaddr(m, dir, flag, error) struct mbuf *m; + u_int dir; int flag; int *error; { @@ -339,20 +330,23 @@ ipsec4_getpolicybyaddr(m, flag, error) panic("ipsec4_getpolicybyaddr: NULL pointer was passed.\n"); { - struct secindex idx; + struct secpolicyindex spidx; - bzero(&idx, sizeof(idx)); + bzero(&spidx, sizeof(spidx)); /* make a index to look for a policy */ - if ((flag & IP_FORWARDING) == IP_FORWARDING) - *error = ipsec_setsecidx(&idx, AF_INET, m, 2); - else - *error = ipsec_setsecidx(&idx, AF_INET, m, 1); + if ((flag & IP_FORWARDING) == IP_FORWARDING) { + /* Case: IP forwarding */ + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m); + } else { + /* Case: ICMP echo reply */ + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m); + } if (*error != 0) return NULL; - sp = key_allocsp(&idx); + sp = key_allocsp(&spidx, dir); } /* SP found */ @@ -367,9 +361,9 @@ ipsec4_getpolicybyaddr(m, flag, error) /* no SP found */ if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD && ip4_def_policy.policy != IPSEC_POLICY_NONE) { - printf("fixed system default policy:%d->%d\n", + ipseclog((LOG_INFO, "fixed system default policy:%d->%d\n", ip4_def_policy.policy, - IPSEC_POLICY_NONE); + IPSEC_POLICY_NONE)); ip4_def_policy.policy = IPSEC_POLICY_NONE; } ip4_def_policy.refcnt++; @@ -389,65 +383,71 @@ ipsec4_getpolicybyaddr(m, flag, error) * others: a pointer to SP */ struct secpolicy * -ipsec6_getpolicybysock(m, so, error) +ipsec6_getpolicybysock(m, dir, so, error) struct mbuf *m; + u_int dir; struct socket *so; int *error; { - struct in6pcb *in6p = sotoin6pcb(so); - struct secpolicy *sp = NULL; - int priv = 0; + struct inpcbpolicy *pcbsp = NULL; + struct secpolicy *currsp = NULL; /* policy on socket */ + struct secpolicy *kernsp = NULL; /* policy on kernel */ /* sanity check */ if (m == NULL || so == NULL || error == NULL) panic("ipsec6_getpolicybysock: NULL pointer was passed.\n"); - if (in6p == NULL) - panic("ipsec6_getpolicybysock: no PCB found.\n"); - if (in6p->in6p_sp == NULL) - panic("ipsec6_getpolicybysock: PCB's SP is NULL.\n"); - if (in6p->in6p_socket == NULL) - panic("ipsec6_getpolicybysock: no socket found.\n"); + + /* set spidx in pcb */ + ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); + + pcbsp = sotoin6pcb(so)->in6p_sp; + + /* sanity check */ + if (pcbsp == NULL) + panic("ipsec6_getpolicybysock: pcbsp is NULL.\n"); + + switch (dir) { + case IPSEC_DIR_INBOUND: + currsp = pcbsp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + currsp = pcbsp->sp_out; + break; + default: + panic("ipsec6_getpolicybysock: illegal direction.\n"); + } + + /* sanity check */ + if (currsp == NULL) + panic("ipsec6_getpolicybysock: currsp is NULL.\n"); /* when privilieged socket */ - if (so->so_uid == 0) /*XXX*/ - priv = 1; - else - priv = 0; - if (priv) { - switch (in6p->in6p_sp->policy) { + if (pcbsp->priv) { + switch (currsp->policy) { case IPSEC_POLICY_BYPASS: - in6p->in6p_sp->refcnt++; + currsp->refcnt++; *error = 0; - return in6p->in6p_sp; + return currsp; case IPSEC_POLICY_ENTRUST: - { - struct secindex idx; - - /* make a index to look for a policy */ - bzero(&idx, sizeof(idx)); - *error = ipsec_setsecidx(&idx, AF_INET6, m, 1); - if (*error != 0) - return NULL; - - sp = key_allocsp(&idx); - } + /* look for a policy in SPD */ + kernsp = key_allocsp(&currsp->spidx, dir); /* SP found */ - if (sp != NULL) { + if (kernsp != NULL) { KEYDEBUG(KEYDEBUG_IPSEC_STAMP, printf("DP ipsec6_getpolicybysock called " - "to allocate SP:%p\n", sp)); + "to allocate SP:%p\n", kernsp)); *error = 0; - return sp; + return kernsp; } /* no SP found */ if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD && ip6_def_policy.policy != IPSEC_POLICY_NONE) { - printf("fixed system default policy:%d->%d\n", - ip6_def_policy.policy, - IPSEC_POLICY_NONE); + ipseclog((LOG_INFO, + "fixed system default policy: %d->%d\n", + ip6_def_policy.policy, IPSEC_POLICY_NONE)); ip6_def_policy.policy = IPSEC_POLICY_NONE; } ip6_def_policy.refcnt++; @@ -455,15 +455,13 @@ ipsec6_getpolicybysock(m, so, error) return &ip6_def_policy; case IPSEC_POLICY_IPSEC: - in6p->in6p_sp->refcnt++; - ipsec_setsecidx(&in6p->in6p_sp->idx, AF_INET6, m, 1); + currsp->refcnt++; *error = 0; - return in6p->in6p_sp; + return currsp; default: - printf("ipsec6_getpolicybysock: " - "Invalid policy for PCB %d\n", - in6p->in6p_sp->policy); + ipseclog((LOG_ERR, "ipsec6_getpolicybysock: " + "Invalid policy for PCB %d\n", currsp->policy)); *error = EINVAL; return NULL; } @@ -471,41 +469,33 @@ ipsec6_getpolicybysock(m, so, error) } /* when non-privilieged socket */ - { - struct secindex idx; - - bzero(&idx, sizeof(idx)); - /* make a index to look for a policy */ - if ((*error = ipsec_setsecidx(&idx, AF_INET6, m, 1)) != 0) - return NULL; - - sp = key_allocsp(&idx); - } + /* look for a policy in SPD */ + kernsp = key_allocsp(&currsp->spidx, dir); /* SP found */ - if (sp != NULL) { + if (kernsp != NULL) { KEYDEBUG(KEYDEBUG_IPSEC_STAMP, printf("DP ipsec6_getpolicybysock called " - "to allocate SP:%p\n", sp)); + "to allocate SP:%p\n", kernsp)); *error = 0; - return sp; + return kernsp; } /* no SP found */ - switch (in6p->in6p_sp->policy) { + switch (currsp->policy) { case IPSEC_POLICY_BYPASS: - printf("ipsec6_getpolicybysock: " - "Illegal policy for non-priviliged defined %d\n", - in6p->in6p_sp->policy); + ipseclog((LOG_ERR, "ipsec6_getpolicybysock: " + "Illegal policy for non-priviliged defined %d\n", + currsp->policy)); *error = EINVAL; return NULL; case IPSEC_POLICY_ENTRUST: if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD && ip6_def_policy.policy != IPSEC_POLICY_NONE) { - printf("fixed system default policy:%d->%d\n", - ip6_def_policy.policy, - IPSEC_POLICY_NONE); + ipseclog((LOG_INFO, + "fixed system default policy: %d->%d\n", + ip6_def_policy.policy, IPSEC_POLICY_NONE)); ip6_def_policy.policy = IPSEC_POLICY_NONE; } ip6_def_policy.refcnt++; @@ -513,15 +503,14 @@ ipsec6_getpolicybysock(m, so, error) return &ip6_def_policy; case IPSEC_POLICY_IPSEC: - in6p->in6p_sp->refcnt++; - ipsec_setsecidx(&in6p->in6p_sp->idx, AF_INET6, m, 1); + currsp->refcnt++; *error = 0; - return in6p->in6p_sp; + return currsp; default: - printf("ipsec6_policybysock: " - "Invalid policy for PCB %d\n", - in6p->in6p_sp->policy); + ipseclog((LOG_ERR, + "ipsec6_policybysock: Invalid policy for PCB %d\n", + currsp->policy)); *error = EINVAL; return NULL; } @@ -545,8 +534,9 @@ ipsec6_getpolicybysock(m, so, error) #endif struct secpolicy * -ipsec6_getpolicybyaddr(m, flag, error) +ipsec6_getpolicybyaddr(m, dir, flag, error) struct mbuf *m; + u_int dir; int flag; int *error; { @@ -557,20 +547,23 @@ ipsec6_getpolicybyaddr(m, flag, error) panic("ipsec6_getpolicybyaddr: NULL pointer was passed.\n"); { - struct secindex idx; + struct secpolicyindex spidx; - bzero(&idx, sizeof(idx)); + bzero(&spidx, sizeof(spidx)); /* make a index to look for a policy */ - if ((flag & IP_FORWARDING) == IP_FORWARDING) - *error = ipsec_setsecidx(&idx, AF_INET6, m, 2); - else - *error = ipsec_setsecidx(&idx, AF_INET6, m, 1); + if ((flag & IP_FORWARDING) == IP_FORWARDING) { + /* Case: IP forwarding */ + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m); + } else { + /* Case: ICMP echo reply */ + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m); + } if (*error != 0) return NULL; - sp = key_allocsp(&idx); + sp = key_allocsp(&spidx, dir); } /* SP found */ @@ -585,9 +578,8 @@ ipsec6_getpolicybyaddr(m, flag, error) /* no SP found */ if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD && ip6_def_policy.policy != IPSEC_POLICY_NONE) { - printf("fixed system default policy:%d->%d\n", - ip6_def_policy.policy, - IPSEC_POLICY_NONE); + ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", + ip6_def_policy.policy, IPSEC_POLICY_NONE)); ip6_def_policy.policy = IPSEC_POLICY_NONE; } ip6_def_policy.refcnt++; @@ -597,34 +589,39 @@ ipsec6_getpolicybyaddr(m, flag, error) #endif /* INET6 */ /* - * seting the values for address from mbuf to secindex structure allocated. - * IN: according to flag, taking the followings from mbuf. - * == 1: protocol family, src, dst, next protocol, src port, dst port. - * This function is called before fragment and after reassemble. - * == 2: protocol family, src, dst, next protocol. - * For the forwarding packet. - * == 3: protocol family, src, dst, security protocol, spi. - * XXX reserved for inbound processing. ?? + * set IP address into spidx from mbuf. + * When Forwarding packet and ICMP echo reply, this function is used. + * + * IN: get the followings from mbuf. + * protocol family, src, dst, next protocol * OUT: - * 0: success. - * 1: failure. + * 0: success. + * other: failure, and set errno. */ int -ipsec_setsecidx(idx, family, m, flag) - struct secindex *idx; - u_int family; +ipsec_setspidx_mbuf(spidx, dir, family, m) + struct secpolicyindex *spidx; + u_int dir, family; struct mbuf *m; - int flag; { + struct sockaddr *sa1, *sa2; + /* sanity check */ - if (idx == NULL || m == NULL) - panic("ipsec_setsecidx: NULL pointer was passed.\n"); + if (spidx == NULL || m == NULL) + panic("ipsec_setspidx_mbuf: NULL pointer was passed.\n"); KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setsecidx: begin\n"); kdebug_mbuf(m)); + printf("ipsec_setspidx_mbuf: begin\n"); kdebug_mbuf(m)); - idx->family = family; - idx->prefs = idx->prefd = _INALENBYAF(family) << 3; + /* initialize */ + bzero(spidx, sizeof(*spidx)); + + spidx->dir = dir; + sa1 = (struct sockaddr *)&spidx->src; + sa2 = (struct sockaddr *)&spidx->dst; + sa1->sa_len = sa2->sa_len = _SALENBYAF(family); + sa1->sa_family = sa2->sa_family = family; + spidx->prefs = spidx->prefd = _INALENBYAF(family) << 3; { /* sanity check for packet length. */ @@ -636,7 +633,7 @@ ipsec_setsecidx(idx, family, m, flag) tlen += n->m_len; if (m->m_pkthdr.len != tlen) { KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setsecidx: " + printf("ipsec_setspidx_mbuf: " "total of m_len(%d) != pkthdr.len(%d), " "ignored.\n", tlen, m->m_pkthdr.len)); @@ -646,14 +643,14 @@ ipsec_setsecidx(idx, family, m, flag) switch (family) { case AF_INET: - { + { struct ip *ip; struct ip ipbuf; /* sanity check 1 for minimum ip header length */ if (m->m_pkthdr.len < sizeof(struct ip)) { KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setsecidx: " + printf("ipsec_setspidx_mbuf: " "pkthdr.len(%d) < sizeof(struct ip), " "ignored.\n", m->m_pkthdr.len)); @@ -672,101 +669,27 @@ ipsec_setsecidx(idx, family, m, flag) } /* some more checks on IPv4 header. */ -#if 0 - /* - * Since {udp,tcp}_input overwrites ip_v field by struct ipovly, - * this check is useless. - */ -#ifdef _IP_VHL - if (IP_VHL_V(ip->ip_vhl) != IPVERSION) -#else - if (ip->ip_v != IPVERSION) -#endif - { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setsecidx: " - "wrong ip version on packet " - "(expected IPv4), ignored.\n")); - goto bad; - } -#endif + bcopy(&ip->ip_src, _INADDRBYSA(&spidx->src), + sizeof(ip->ip_src)); + bcopy(&ip->ip_dst, _INADDRBYSA(&spidx->dst), + sizeof(ip->ip_dst)); - idx->proto = ip->ip_p; - bcopy(&ip->ip_src, &idx->src, sizeof(ip->ip_src)); - bcopy(&ip->ip_dst, &idx->dst, sizeof(ip->ip_dst)); - - switch (flag) { - case 1: - /* get port numbers from next protocol header */ - switch (ip->ip_p) { - case IPPROTO_TCP: - case IPPROTO_UDP: - { - int len; - u_short ports, portd; - - /* sanity check */ - /* set ip header length */ - if (ip->ip_hl == 0) { - /* - * In upper layer stack, - * it is set zero to - * some values in ipovly. - */ - len = sizeof(struct ip); - } else { -#ifdef _IP_VHL - len = _IP_VHL_HL(ip->ip_vhl) << 2; -#else - len = ip->ip_hl << 2; -#endif - } - - if (m->m_pkthdr.len < len + 4) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setsecidx: " - "pkthdr.len(%d) too short to " - "get port number information, " - "ignored.\n", - m->m_pkthdr.len)); - goto bad; - } - - m_copydata(m, len, 2, (caddr_t)&ports); - m_copydata(m, len + 2, 2, (caddr_t)&portd); -#if 0 - idx->ports = ntohs(ports); - idx->portd = ntohs(portd); -#else - idx->ports = ports; - idx->portd = portd; -#endif - } - break; - - case IPPROTO_ICMP: - default: - idx->ports = 0; - idx->portd = 0; - } - break; - case 2: - break; - case 3: - break; - } - } + spidx->ul_proto = ip->ip_p; + _INPORTBYSA(&spidx->src) = IPSEC_PORT_ANY; + _INPORTBYSA(&spidx->dst) = IPSEC_PORT_ANY; break; + } + #ifdef INET6 case AF_INET6: - { + { struct ip6_hdr *ip6_hdr; struct ip6_hdr ip6buf; /* sanity check 1 for minimum ip header length */ if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setsecidx: " + printf("ipsec_setspidx_mbuf: " "pkthdr.len(%d) < sizeof(struct ip6_hdr), " "ignored.\n", m->m_pkthdr.len)); @@ -787,110 +710,392 @@ ipsec_setsecidx(idx, family, m, flag) /* some more checks on IPv4 header. */ if ((ip6_hdr->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setsecidx: " + printf("ipsec_setspidx_mbuf: " "wrong ip version on packet " "(expected IPv6), ignored.\n")); goto bad; } - idx->proto = 0; /* XXX */ - bcopy(&ip6_hdr->ip6_src, &idx->src, sizeof(ip6_hdr->ip6_src)); - bcopy(&ip6_hdr->ip6_dst, &idx->dst, sizeof(ip6_hdr->ip6_dst)); + bcopy(&ip6_hdr->ip6_src, _INADDRBYSA(&spidx->src), + sizeof(ip6_hdr->ip6_src)); + bcopy(&ip6_hdr->ip6_dst, _INADDRBYSA(&spidx->dst), + sizeof(ip6_hdr->ip6_dst)); -#if 0 /* XXX Do it ! */ - switch (flag) { - case 1: - /* get port numbers from next protocol header */ - switch (ip6->ip6_nxt) { - /* fragmented case ... */ - case IPPROTO_TCP: - case IPPROTO_UDP: - break; - case IPPROTO_ICMPV6: - default: - idx->proto = 0; /* i.e. ignore */ - idx->ports = 0; - idx->portd = 0; - } - break; - case 2: - case 3: - } -#else - idx->proto = 0; /* i.e. ignore */ - idx->ports = 0; - idx->portd = 0; -#endif - } + ipsec6_get_ulp(m, spidx); break; + } #endif /* INET6 */ default: panic("ipsec_secsecidx: no supported family passed.\n"); } KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setsecidx: end\n"); kdebug_secindex(idx)); + printf("ipsec_setspidx_mbuf: end\n"); + kdebug_secpolicyindex(spidx)); return 0; bad: /* XXX initialize */ - bzero(idx, sizeof(*idx)); - return -1; + bzero(spidx, sizeof(*spidx)); + return EINVAL; } -#if 0 +#ifdef INET6 +/* + * Get upper layer protocol number and port number if there. + * Assumed all extension headers are in single mbuf. + */ +#include +#include static void -ipsec_setsecidx_pcb(idx, family, ip_p, laddr, lport, faddr, fport) - struct secindex *idx; - u_int family, ip_p, lport, fport; - void *laddr, *faddr; +ipsec6_get_ulp(m, spidx) + struct mbuf *m; + struct secpolicyindex *spidx; { - printf("family:%u ip_p:%u pref:%u\n", - family, ip_p, _INALENBYAF(family)); - ipsec_hexdump(laddr, _INALENBYAF(family)), - printf(" lport:%u\n", ntohs(lport)); - ipsec_hexdump(faddr, _INALENBYAF(family)), - printf(" fport:%u\n", ntohs(fport)); + struct ip6_hdr *ip6; + struct ip6_ext *ip6e; + int off, nxt; + int len; - idx->family = family; - idx->prefs = _INALENBYAF(family) << 8; - idx->prefd = _INALENBYAF(family) << 8; - idx->proto = ip_p; - idx->ports = lport; - idx->portd = fport; - idx->src = (caddr_t)laddr; - idx->dst = (caddr_t)faddr; + /* sanity check */ + if (m == NULL) + panic("ipsec6_get_ulp: NULL pointer was passed.\n"); + + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m)); + + /* set default */ + spidx->ul_proto = IPSEC_ULPROTO_ANY; + _INPORTBYSA(&spidx->src) = IPSEC_PORT_ANY; + _INPORTBYSA(&spidx->dst) = IPSEC_PORT_ANY; + + ip6 = mtod(m, struct ip6_hdr *); + nxt = ip6->ip6_nxt; + off = sizeof(struct ip6_hdr); + len = m->m_len; + + while (off < len) { + ip6e = (struct ip6_ext *)((caddr_t) ip6 + off); + if (m->m_len < off + sizeof(*ip6e)) { + ipseclog((LOG_DEBUG, "ipsec6_get_ulp: all exthdr are " + "not in single mbuf.\n")); + return; + } + + switch(nxt) { + case IPPROTO_TCP: + spidx->ul_proto = nxt; + _INPORTBYSA(&spidx->src) = + ((struct tcphdr *)((caddr_t)ip6 + off))->th_sport; + _INPORTBYSA(&spidx->dst) = + ((struct tcphdr *)((caddr_t)ip6 + off))->th_dport; + return; + case IPPROTO_UDP: + spidx->ul_proto = nxt; + _INPORTBYSA(&spidx->src) = + ((struct udphdr *)((caddr_t)ip6 + off))->uh_sport; + _INPORTBYSA(&spidx->dst) = + ((struct udphdr *)((caddr_t)ip6 + off))->uh_dport; + return; + case IPPROTO_ICMPV6: + spidx->ul_proto = nxt; + return; + case IPPROTO_FRAGMENT: + off += sizeof(struct ip6_frag); + break; + case IPPROTO_AH: + off += (ip6e->ip6e_len + 2) << 2; + break; + default: + switch (nxt) { + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_NONE: + case IPPROTO_DSTOPTS: + break; + case IPPROTO_ESP: + case IPPROTO_IPCOMP: + /* give up */ + return; + default: + return; /* XXX */ + } + off += (ip6e->ip6e_len + 1) << 3; + break; + } + nxt = ip6e->ip6e_nxt; + } return; } #endif +static void +ipsec4_setspidx_inpcb(m, pcb) + struct mbuf *m; + struct inpcb *pcb; +{ + struct secpolicyindex *spidx; + struct sockaddr *sa1, *sa2; + + /* sanity check */ + if (pcb == NULL) + panic("ipsec4_setspidx_inpcb: no PCB found.\n"); + if (pcb->inp_sp == NULL) + panic("ipsec4_setspidx_inpcb: no inp_sp found.\n"); + if (pcb->inp_sp->sp_out ==NULL || pcb->inp_sp->sp_in == NULL) + panic("ipsec4_setspidx_inpcb: no sp_in/out found.\n"); + + bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx)); + + spidx = &pcb->inp_sp->sp_in->spidx; + spidx->dir = IPSEC_DIR_INBOUND; + sa1 = (struct sockaddr *)&spidx->src; + sa2 = (struct sockaddr *)&spidx->dst; + sa1->sa_len = sa2->sa_len = _SALENBYAF(AF_INET); + sa1->sa_family = sa2->sa_family = AF_INET; + spidx->prefs = _INALENBYAF(AF_INET) << 3; + spidx->prefd = _INALENBYAF(AF_INET) << 3; + spidx->ul_proto = pcb->inp_socket->so_proto->pr_protocol; + _INPORTBYSA(&spidx->src) = pcb->inp_fport; + _INPORTBYSA(&spidx->dst) = pcb->inp_lport; + ipsec4_setspidx_ipaddr(m, spidx); + + spidx = &pcb->inp_sp->sp_out->spidx; + spidx->dir = IPSEC_DIR_OUTBOUND; + sa1 = (struct sockaddr *)&spidx->src; + sa2 = (struct sockaddr *)&spidx->dst; + sa1->sa_len = sa2->sa_len = _SALENBYAF(AF_INET); + sa1->sa_family = sa2->sa_family = AF_INET; + spidx->prefs = _INALENBYAF(AF_INET) << 3; + spidx->prefd = _INALENBYAF(AF_INET) << 3; + spidx->ul_proto = pcb->inp_socket->so_proto->pr_protocol; + _INPORTBYSA(&spidx->src) = pcb->inp_lport; + _INPORTBYSA(&spidx->dst) = pcb->inp_fport; + ipsec4_setspidx_ipaddr(m, spidx); + + return; +} + +static void +ipsec4_setspidx_ipaddr(m, spidx) + struct mbuf *m; + struct secpolicyindex *spidx; +{ + struct ip *ip = NULL; + struct ip ipbuf; + + /* sanity check 1 for minimum ip header length */ + if (m == NULL) + panic("ipsec4_setspidx_in6pcb: m == 0 passed.\n"); + + if (m->m_pkthdr.len < sizeof(struct ip)) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec4_setspidx_ipaddr: " + "pkthdr.len(%d) < sizeof(struct ip), " + "ignored.\n", + m->m_pkthdr.len)); + return; + } + + if (m->m_len >= sizeof(*ip)) + ip = mtod(m, struct ip *); + else { + m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); + ip = &ipbuf; + } + + bcopy(&ip->ip_src, _INADDRBYSA(&spidx->src), sizeof(ip->ip_src)); + bcopy(&ip->ip_dst, _INADDRBYSA(&spidx->dst), sizeof(ip->ip_dst)); + + return; +} + +#ifdef INET6 +static void +ipsec6_setspidx_in6pcb(m, pcb) + struct mbuf *m; + struct in6pcb *pcb; +{ + struct secpolicyindex *spidx; + struct sockaddr *sa1, *sa2; + + /* sanity check */ + if (pcb == NULL) + panic("ipsec6_setspidx_in6pcb: no PCB found.\n"); + if (pcb->in6p_sp == NULL) + panic("ipsec6_setspidx_in6pcb: no in6p_sp found.\n"); + if (pcb->in6p_sp->sp_out ==NULL || pcb->in6p_sp->sp_in == NULL) + panic("ipsec6_setspidx_in6pcb: no sp_in/out found.\n"); + + bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); + + spidx = &pcb->in6p_sp->sp_in->spidx; + spidx->dir = IPSEC_DIR_INBOUND; + sa1 = (struct sockaddr *)&spidx->src; + sa2 = (struct sockaddr *)&spidx->dst; + sa1->sa_len = sa2->sa_len = _SALENBYAF(AF_INET6); + sa1->sa_family = sa2->sa_family = AF_INET6; + spidx->prefs = _INALENBYAF(AF_INET6) << 3; + spidx->prefd = _INALENBYAF(AF_INET6) << 3; + spidx->ul_proto = pcb->in6p_socket->so_proto->pr_protocol; + _INPORTBYSA(&spidx->src) = pcb->in6p_fport; + _INPORTBYSA(&spidx->dst) = pcb->in6p_lport; + ipsec6_setspidx_ipaddr(m, spidx); + + spidx = &pcb->in6p_sp->sp_out->spidx; + spidx->dir = IPSEC_DIR_OUTBOUND; + sa1 = (struct sockaddr *)&spidx->src; + sa2 = (struct sockaddr *)&spidx->dst; + sa1->sa_len = sa2->sa_len = _SALENBYAF(AF_INET6); + sa1->sa_family = sa2->sa_family = AF_INET6; + spidx->prefs = _INALENBYAF(AF_INET6) << 3; + spidx->prefd = _INALENBYAF(AF_INET6) << 3; + spidx->ul_proto = pcb->in6p_socket->so_proto->pr_protocol; + _INPORTBYSA(&spidx->src) = pcb->in6p_lport; + _INPORTBYSA(&spidx->dst) = pcb->in6p_fport; + ipsec6_setspidx_ipaddr(m, spidx); + + return; +} + +static void +ipsec6_setspidx_ipaddr(m, spidx) + struct mbuf *m; + struct secpolicyindex *spidx; +{ + struct ip6_hdr *ip6_hdr = NULL; + struct ip6_hdr ip6buf; + + /* sanity check 1 for minimum ip header length */ + if (m == NULL) + panic("ipsec6_setspidx_in6pcb: m == 0 passed.\n"); + + if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec6_setspidx_ipaddr: " + "pkthdr.len(%d) < sizeof(struct ip6_hdr), " + "ignored.\n", + m->m_pkthdr.len)); + return; + } + + if (m->m_len >= sizeof(*ip6_hdr)) + ip6_hdr = mtod(m, struct ip6_hdr *); + else { + m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); + ip6_hdr = &ip6buf; + } + + if ((ip6_hdr->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx_mbuf: " + "wrong ip version on packet " + "(expected IPv6), ignored.\n")); + return; + } + + bcopy(&ip6_hdr->ip6_src, _INADDRBYSA(&spidx->src), + sizeof(ip6_hdr->ip6_src)); + bcopy(&ip6_hdr->ip6_dst, _INADDRBYSA(&spidx->dst), + sizeof(ip6_hdr->ip6_dst)); + + return; +} +#endif + +static struct inpcbpolicy * +ipsec_newpcbpolicy() +{ + struct inpcbpolicy *p; + + p = (struct inpcbpolicy *)malloc(sizeof(*p), M_SECA, M_NOWAIT); + return p; +} + +static void +ipsec_delpcbpolicy(p) + struct inpcbpolicy *p; +{ + free(p, M_SECA); +} + /* initialize policy in PCB */ int -ipsec_init_policy(pcb_sp) - struct secpolicy **pcb_sp; +ipsec_init_policy(so, pcb_sp) + struct socket *so; + struct inpcbpolicy **pcb_sp; { - struct secpolicy *newsp; + struct inpcbpolicy *new; /* sanity check. */ - if (pcb_sp == NULL) + if (so == NULL || pcb_sp == NULL) panic("ipsec_init_policy: NULL pointer was passed.\n"); - if ((newsp = key_newsp()) == NULL) + new = ipsec_newpcbpolicy(); + if (new == NULL) { + ipseclog((LOG_DEBUG, "ipsec_init_policy: No more memory.\n")); + return ENOBUFS; + } + bzero(new, sizeof(*new)); + + if (so->so_uid == 0) /*XXX*/ + new->priv = 1; + else + new->priv = 0; + + if ((new->sp_in = key_newsp()) == NULL) { + ipsec_delpcbpolicy(new); + return ENOBUFS; + } + new->sp_in->state = IPSEC_SPSTATE_ALIVE; + new->sp_in->policy = IPSEC_POLICY_ENTRUST; + + if ((new->sp_out = key_newsp()) == NULL) { + key_freesp(new->sp_in); + ipsec_delpcbpolicy(new); + return ENOBUFS; + } + new->sp_out->state = IPSEC_SPSTATE_ALIVE; + new->sp_out->policy = IPSEC_POLICY_ENTRUST; + + *pcb_sp = new; + + return 0; +} + +/* copy old ipsec policy into new */ +int +ipsec_copy_policy(old, new) + struct inpcbpolicy *old, *new; +{ + struct secpolicy *sp; + + sp = ipsec_deepcopy_policy(old->sp_in); + if (sp) { + key_freesp(new->sp_in); + new->sp_in = sp; + } else return ENOBUFS; - newsp->state = IPSEC_SPSTATE_ALIVE; - newsp->policy = IPSEC_POLICY_ENTRUST; + sp = ipsec_deepcopy_policy(old->sp_out); + if (sp) { + key_freesp(new->sp_out); + new->sp_out = sp; + } else + return ENOBUFS; - *pcb_sp = newsp; + new->priv = old->priv; return 0; } /* deep-copy a policy in PCB */ -struct secpolicy * -ipsec_copy_policy(src) +static struct secpolicy * +ipsec_deepcopy_policy(src) struct secpolicy *src; { struct ipsecrequest *newchain = NULL; @@ -909,23 +1114,22 @@ ipsec_copy_policy(src) */ q = &newchain; for (p = src->req; p; p = p->next) { - KMALLOC(*q, struct ipsecrequest *, sizeof(struct ipsecrequest)); + *q = (struct ipsecrequest *)malloc(sizeof(struct ipsecrequest), + M_SECA, M_NOWAIT); if (*q == NULL) goto fail; bzero(*q, sizeof(**q)); (*q)->next = NULL; - (*q)->proto = p->proto; - (*q)->mode = p->mode; + + (*q)->saidx.proto = p->saidx.proto; + (*q)->saidx.mode = p->saidx.mode; (*q)->level = p->level; - (*q)->proxy = NULL; - if (p->proxy) { - KMALLOC((*q)->proxy, struct sockaddr *, - p->proxy->sa_len); - if ((*q)->proxy == NULL) - goto fail; - bcopy(p->proxy, (*q)->proxy, p->proxy->sa_len); - } - (*q)->sa = NULL; + (*q)->saidx.reqid = p->saidx.reqid; + + bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src)); + bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst)); + + (*q)->sav = NULL; (*q)->sp = dst; q = &((*q)->next); @@ -934,7 +1138,6 @@ ipsec_copy_policy(src) dst->req = newchain; dst->state = src->state; dst->policy = src->policy; - dst->state = src->state; /* do not touch the refcnt fields */ return dst; @@ -942,33 +1145,34 @@ ipsec_copy_policy(src) fail: for (p = newchain; p; p = r) { r = p->next; - if (p->proxy) { - KFREE(p->proxy); - p->proxy = NULL; - } - KFREE(p); + free(p, M_SECA); p = NULL; } return NULL; } /* set policy and ipsec request if present. */ -int -ipsec_set_policy(pcb_sp, optname, request, reqlen, priv) +static int +ipsec_set_policy(pcb_sp, optname, request, len, priv) struct secpolicy **pcb_sp; - int optname, reqlen; + int optname; caddr_t request; + size_t len; int priv; { - struct sadb_x_policy *xpl = (struct sadb_x_policy *)request; + struct sadb_x_policy *xpl; struct secpolicy *newsp = NULL; + int error; /* sanity check. */ if (pcb_sp == NULL || *pcb_sp == NULL || xpl == NULL) return EINVAL; + if (len < sizeof(*xpl)) + return EINVAL; + xpl = (struct sadb_x_policy *)request; KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_set_policy:\n"); + printf("ipsec_set_policy: passed policy\n"); kdebug_sadb_x_policy((struct sadb_ext *)xpl)); /* check policy type */ @@ -982,8 +1186,8 @@ ipsec_set_policy(pcb_sp, optname, request, reqlen, priv) return EACCES; /* allocation new SP entry */ - if ((newsp = key_msg2sp(xpl)) == NULL) - return EINVAL; /* maybe ENOBUFS */ + if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) + return error; newsp->state = IPSEC_SPSTATE_ALIVE; @@ -991,55 +1195,104 @@ ipsec_set_policy(pcb_sp, optname, request, reqlen, priv) key_freesp(*pcb_sp); *pcb_sp = newsp; KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_set_policy:\n"); + printf("ipsec_set_policy: new policy\n"); kdebug_secpolicy(newsp)); return 0; } -int +static int ipsec_get_policy(pcb_sp, mp) struct secpolicy *pcb_sp; struct mbuf **mp; { - struct sadb_x_policy *xpl; /* sanity check. */ if (pcb_sp == NULL || mp == NULL) return EINVAL; - if ((xpl = key_sp2msg(pcb_sp)) == NULL) { - printf("ipsec_get_policy: No more memory.\n"); + *mp = key_sp2msg(pcb_sp); + if (!*mp) { + ipseclog((LOG_DEBUG, "ipsec_get_policy: No more memory.\n")); return ENOBUFS; } - *mp = m_get(M_WAIT, MT_SOOPTS); - (*mp)->m_len = PFKEY_EXTLEN(xpl); - m_copyback((*mp), 0, PFKEY_EXTLEN(xpl), (caddr_t)xpl); + (*mp)->m_type = MT_SOOPTS; KEYDEBUG(KEYDEBUG_IPSEC_DUMP, printf("ipsec_get_policy:\n"); kdebug_mbuf(*mp)); - KFREE(xpl); - return 0; } -#if 0 -/* delete policy */ -static int -ipsec_delete_policy(sp) - struct secpolicy *sp; +int +ipsec4_set_policy(inp, optname, request, len, priv) + struct inpcb *inp; + int optname; + caddr_t request; + size_t len; + int priv; { + struct sadb_x_policy *xpl; + struct secpolicy **pcb_sp; + /* sanity check. */ - if (sp == NULL) - panic("ipsec_delete_policy: NULL pointer was passed.\n"); + if (inp == NULL || request == NULL) + return EINVAL; + if (len < sizeof(*xpl)) + return EINVAL; + xpl = (struct sadb_x_policy *)request; - key_freesp(sp); + /* select direction */ + switch (xpl->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + pcb_sp = &inp->inp_sp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + pcb_sp = &inp->inp_sp->sp_out; + break; + default: + ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n", + xpl->sadb_x_policy_dir)); + return EINVAL; + } - return 0; + return ipsec_set_policy(pcb_sp, optname, request, len, priv); +} + +int +ipsec4_get_policy(inp, request, len, mp) + struct inpcb *inp; + caddr_t request; + size_t len; + struct mbuf **mp; +{ + struct sadb_x_policy *xpl; + struct secpolicy *pcb_sp; + + /* sanity check. */ + if (inp == NULL || request == NULL || mp == NULL) + return EINVAL; + if (len != sizeof(*xpl)) + return EINVAL; + xpl = (struct sadb_x_policy *)request; + + /* select direction */ + switch (xpl->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + pcb_sp = inp->inp_sp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + pcb_sp = inp->inp_sp->sp_out; + break; + default: + ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n", + xpl->sadb_x_policy_dir)); + return EINVAL; + } + + return ipsec_get_policy(pcb_sp, mp); } -#endif /* delete policy in PCB */ int @@ -1048,18 +1301,94 @@ ipsec4_delete_pcbpolicy(inp) { /* sanity check. */ if (inp == NULL) - panic("ipsec6_delete_pcbpolicy: NULL pointer was passed.\n"); + panic("ipsec4_delete_pcbpolicy: NULL pointer was passed.\n"); - if (inp->inp_sp == NULL) - return 0; + if (inp->inp_sp->sp_in != NULL) { + key_freesp(inp->inp_sp->sp_in); + inp->inp_sp->sp_in = NULL; + } - key_freesp(inp->inp_sp); + if (inp->inp_sp->sp_out != NULL) { + key_freesp(inp->inp_sp->sp_out); + inp->inp_sp->sp_out = NULL; + } + + ipsec_delpcbpolicy(inp->inp_sp); inp->inp_sp = NULL; return 0; } #ifdef INET6 +int +ipsec6_set_policy(in6p, optname, request, len, priv) + struct in6pcb *in6p; + int optname; + caddr_t request; + size_t len; + int priv; +{ + struct sadb_x_policy *xpl; + struct secpolicy **pcb_sp; + + /* sanity check. */ + if (in6p == NULL || request == NULL) + return EINVAL; + if (len < sizeof(*xpl)) + return EINVAL; + xpl = (struct sadb_x_policy *)request; + + /* select direction */ + switch (xpl->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + pcb_sp = &in6p->in6p_sp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + pcb_sp = &in6p->in6p_sp->sp_out; + break; + default: + ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n", + xpl->sadb_x_policy_dir)); + return EINVAL; + } + + return ipsec_set_policy(pcb_sp, optname, request, len, priv); +} + +int +ipsec6_get_policy(in6p, request, len, mp) + struct in6pcb *in6p; + caddr_t request; + size_t len; + struct mbuf **mp; +{ + struct sadb_x_policy *xpl; + struct secpolicy *pcb_sp; + + /* sanity check. */ + if (in6p == NULL || request == NULL || mp == NULL) + return EINVAL; + if (len != sizeof(*xpl)) + return EINVAL; + xpl = (struct sadb_x_policy *)request; + + /* select direction */ + switch (xpl->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + pcb_sp = in6p->in6p_sp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + pcb_sp = in6p->in6p_sp->sp_out; + break; + default: + ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n", + xpl->sadb_x_policy_dir)); + return EINVAL; + } + + return ipsec_get_policy(pcb_sp, mp); +} + int ipsec6_delete_pcbpolicy(in6p) struct in6pcb *in6p; @@ -1068,10 +1397,17 @@ ipsec6_delete_pcbpolicy(in6p) if (in6p == NULL) panic("ipsec6_delete_pcbpolicy: NULL pointer was passed.\n"); - if (in6p->in6p_sp == NULL) - return 0; + if (in6p->in6p_sp->sp_in != NULL) { + key_freesp(in6p->in6p_sp->sp_in); + in6p->in6p_sp->sp_in = NULL; + } - key_freesp(in6p->in6p_sp); + if (in6p->in6p_sp->sp_out != NULL) { + key_freesp(in6p->in6p_sp->sp_out); + in6p->in6p_sp->sp_out = NULL; + } + + ipsec_delpcbpolicy(in6p->in6p_sp); in6p->in6p_sp = NULL; return 0; @@ -1080,7 +1416,7 @@ ipsec6_delete_pcbpolicy(in6p) /* * return current level. - * IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. + * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. */ u_int ipsec_get_reqlevel(isr) @@ -1092,15 +1428,24 @@ ipsec_get_reqlevel(isr) /* sanity check */ if (isr == NULL || isr->sp == NULL) panic("ipsec_get_reqlevel: NULL pointer is passed.\n"); + if (((struct sockaddr *)&isr->sp->spidx.src)->sa_family + != ((struct sockaddr *)&isr->sp->spidx.dst)->sa_family) + panic("ipsec_get_reqlevel: family mismatched.\n"); +/* XXX note that we have ipseclog() expanded here - code sync issue */ #define IPSEC_CHECK_DEFAULT(lev) \ - (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE) \ - ? (printf("fixed system default level " #lev ":%d->%d\n", \ - (lev), IPSEC_LEVEL_USE), \ - (lev) = IPSEC_LEVEL_USE) : (lev)) + (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \ + && (lev) != IPSEC_LEVEL_UNIQUE) \ + ? (ipsec_debug \ + ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ + (lev), IPSEC_LEVEL_REQUIRE) \ + : 0), \ + (lev) = IPSEC_LEVEL_REQUIRE, \ + (lev) \ + : (lev)) /* set default level */ - switch (isr->sp->idx.family) { + switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) { #ifdef INET case AF_INET: esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_trans_deflev); @@ -1119,7 +1464,7 @@ ipsec_get_reqlevel(isr) #endif /* INET6 */ default: panic("key_get_reqlevel: Unknown family. %d\n", - isr->sp->idx.family); + ((struct sockaddr *)&isr->sp->spidx.src)->sa_family); } #undef IPSEC_CHECK_DEFAULT(lev) @@ -1127,15 +1472,15 @@ ipsec_get_reqlevel(isr) /* set level */ switch (isr->level) { case IPSEC_LEVEL_DEFAULT: - switch (isr->proto) { + switch (isr->saidx.proto) { case IPPROTO_ESP: - if (isr->mode == IPSEC_MODE_TUNNEL) + if (isr->saidx.mode == IPSEC_MODE_TUNNEL) level = esp_net_deflev; else level = esp_trans_deflev; break; case IPPROTO_AH: - if (isr->mode == IPSEC_MODE_TUNNEL) + if (isr->saidx.mode == IPSEC_MODE_TUNNEL) level = ah_net_deflev; else level = ah_trans_deflev; @@ -1149,7 +1494,7 @@ ipsec_get_reqlevel(isr) default: panic("ipsec_get_reqlevel: " "Illegal protocol defined %u\n", - isr->proto); + isr->saidx.proto); } break; @@ -1157,6 +1502,9 @@ ipsec_get_reqlevel(isr) case IPSEC_LEVEL_REQUIRE: level = isr->level; break; + case IPSEC_LEVEL_UNIQUE: + level = IPSEC_LEVEL_REQUIRE; + break; default: panic("ipsec_get_reqlevel: Illegal IPsec level %u\n", @@ -1210,14 +1558,14 @@ ipsec_in_reject(sp, m) /* get current level */ level = ipsec_get_reqlevel(isr); - switch (isr->proto) { + switch (isr->saidx.proto) { case IPPROTO_ESP: if (level == IPSEC_LEVEL_REQUIRE) { need_conf++; - if (isr->sa != NULL - && isr->sa->flags == SADB_X_EXT_NONE - && isr->sa->alg_auth != SADB_AALG_NONE) + if (isr->sav != NULL + && isr->sav->flags == SADB_X_EXT_NONE + && isr->sav->alg_auth != SADB_AALG_NONE) need_icv++; } break; @@ -1271,9 +1619,9 @@ ipsec4_in_reject_so(m, so) * ipsec4_getpolicybyaddr() with IP_FORWARDING flag. */ if (so == NULL) - sp = ipsec4_getpolicybyaddr(m, IP_FORWARDING, &error); + sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); else - sp = ipsec4_getpolicybysock(m, so, &error); + sp = ipsec4_getpolicybysock(m, IPSEC_DIR_INBOUND, so, &error); if (sp == NULL) return 0; /* XXX should be panic ? @@ -1326,9 +1674,9 @@ ipsec6_in_reject_so(m, so) * ipsec6_getpolicybyaddr() with IP_FORWARDING flag. */ if (so == NULL) - sp = ipsec6_getpolicybyaddr(m, IP_FORWARDING, &error); + sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); else - sp = ipsec6_getpolicybysock(m, so, &error); + sp = ipsec6_getpolicybysock(m, IPSEC_DIR_INBOUND, so, &error); if (sp == NULL) return 0; /* XXX should be panic ? */ @@ -1394,7 +1742,7 @@ ipsec_hdrsiz(sp) clen = 0; - switch (isr->proto) { + switch (isr->saidx.proto) { case IPPROTO_ESP: #ifdef IPSEC_ESP clen = esp_hdrsiz(isr); @@ -1410,17 +1758,8 @@ ipsec_hdrsiz(sp) break; } - if (isr->mode == IPSEC_MODE_TUNNEL -#if 0 /* XXX why ? There may be tunnel mode without IPsec. */ - && clen != 0 -#endif - ) { - /* sanity check */ - if (isr->proxy == NULL) - panic("ipsec_hdrsiz: proxy is NULL " - "but tunnel mode.\n"); - - switch (isr->proxy->sa_family) { + if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { + switch (((struct sockaddr *)&isr->saidx.dst)->sa_family) { case AF_INET: clen += sizeof(struct ip); break; @@ -1430,9 +1769,9 @@ ipsec_hdrsiz(sp) break; #endif default: - printf("ipsec_hdrsiz: unknown AF %d " - "in IPsec tunnel SA\n", - isr->proxy->sa_family); + ipseclog((LOG_ERR, "ipsec_hdrsiz: " + "unknown AF %d in IPsec tunnel SA\n", + ((struct sockaddr *)&isr->saidx.dst)->sa_family)); break; } } @@ -1444,8 +1783,9 @@ ipsec_hdrsiz(sp) /* This function is called from ip_forward() and ipsec4_hdrsize_tcp(). */ size_t -ipsec4_hdrsiz(m, inp) +ipsec4_hdrsiz(m, dir, inp) struct mbuf *m; + u_int dir; struct inpcb *inp; { struct secpolicy *sp = NULL; @@ -1463,9 +1803,9 @@ ipsec4_hdrsiz(m, inp) * ipsec4_getpolicybyaddr() with IP_FORWARDING flag. */ if (inp == NULL) - sp = ipsec4_getpolicybyaddr(m, IP_FORWARDING, &error); + sp = ipsec4_getpolicybyaddr(m, dir, IP_FORWARDING, &error); else - sp = ipsec4_getpolicybysock(m, inp->inp_socket, &error); + sp = ipsec4_getpolicybysock(m, dir, inp->inp_socket, &error); if (sp == NULL) return 0; /* XXX should be panic ? */ @@ -1485,8 +1825,9 @@ ipsec4_hdrsiz(m, inp) * and maybe from ip6_forward.() */ size_t -ipsec6_hdrsiz(m, in6p) +ipsec6_hdrsiz(m, dir, in6p) struct mbuf *m; + u_int dir; struct in6pcb *in6p; { struct secpolicy *sp = NULL; @@ -1502,9 +1843,9 @@ ipsec6_hdrsiz(m, in6p) /* get SP for this packet */ /* XXX Is it right to call with IP_FORWARDING. */ if (in6p == NULL) - sp = ipsec6_getpolicybyaddr(m, IP_FORWARDING, &error); + sp = ipsec6_getpolicybyaddr(m, dir, IP_FORWARDING, &error); else - sp = ipsec6_getpolicybysock(m, in6p->in6p_socket, &error); + sp = ipsec6_getpolicybysock(m, dir, in6p->in6p_socket, &error); if (sp == NULL) return 0; @@ -1525,9 +1866,9 @@ ipsec6_hdrsiz(m, in6p) * ip->ip_src must be fixed later on. */ static int -ipsec4_encapsulate(m, sa) +ipsec4_encapsulate(m, sav) struct mbuf *m; - struct secas *sa; + struct secasvar *sav; { struct ip *oip; struct ip *ip; @@ -1535,13 +1876,15 @@ ipsec4_encapsulate(m, sa) size_t plen; /* can't tunnel between different AFs */ - if (sa->proxy->sa_family != AF_INET) { + if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family + != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family + || ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET) { m_freem(m); return EINVAL; } #if 0 - /* XXX if the proxy is myself, perform nothing. */ - if (sa->saidx && key_ismyaddr(AF_INET, sa->saidx->idx.dst)) { + /* XXX if the dst is myself, perform nothing. */ + if (key_ismyaddr(AF_INET, _INADDRBYSA(&sav->sah->saidx.dst))) { m_freem(m); return EINVAL; } @@ -1620,13 +1963,16 @@ ipsec4_encapsulate(m, sa) if (plen + sizeof(struct ip) < IP_MAXPACKET) ip->ip_len = htons(plen + sizeof(struct ip)); else { - printf("IPv4 ipsec: size exceeds limit: " - "leave ip_len as is (invalid packet)\n"); + ipseclog((LOG_ERR, "IPv4 ipsec: size exceeds limit: " + "leave ip_len as is (invalid packet)\n")); } ip->ip_id = htons(ip_id++); - bcopy(&((struct sockaddr_in *)sa->proxy)->sin_addr, + bcopy(&((struct sockaddr_in *)&sav->sah->saidx.src)->sin_addr, + &ip->ip_src, sizeof(ip->ip_src)); + bcopy(&((struct sockaddr_in *)&sav->sah->saidx.dst)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)); - /* XXX ip_src must be updated later */ + + /* XXX Should ip_src be updated later ? */ return 0; } @@ -1634,22 +1980,24 @@ ipsec4_encapsulate(m, sa) #ifdef INET6 static int -ipsec6_encapsulate(m, sa) +ipsec6_encapsulate(m, sav) struct mbuf *m; - struct secas *sa; + struct secasvar *sav; { struct ip6_hdr *oip6; struct ip6_hdr *ip6; size_t plen; /* can't tunnel between different AFs */ - if (sa->proxy->sa_family != AF_INET6) { + if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family + != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family + || ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET6) { m_freem(m); return EINVAL; } #if 0 - /* XXX if the proxy is myself, perform nothing. */ - if (sa->saidx && key_ismyaddr(AF_INET6, sa->saidx->dst)) { + /* XXX if the dst is myself, perform nothing. */ + if (key_ismyaddr(AF_INET6, _INADDRBYSA(&sav->sah->saidx.dst))) { m_freem(m); return EINVAL; } @@ -1698,9 +2046,12 @@ ipsec6_encapsulate(m, sa) /* ip6->ip6_plen will be updated in ip6_output() */ } ip6->ip6_nxt = IPPROTO_IPV6; - bcopy(&((struct sockaddr_in6 *)sa->proxy)->sin6_addr, + bcopy(&((struct sockaddr_in6 *)&sav->sah->saidx.src)->sin6_addr, + &ip6->ip6_src, sizeof(ip6->ip6_src)); + bcopy(&((struct sockaddr_in6 *)&sav->sah->saidx.dst)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst)); - /* XXX ip6_src must be updated later */ + + /* XXX Should ip6_src be updated later ? */ return 0; } @@ -1717,9 +2068,9 @@ ipsec6_encapsulate(m, sa) * based on RFC 2401. */ int -ipsec_chkreplay(seq, sa) +ipsec_chkreplay(seq, sav) u_int32_t seq; - struct secas *sa; + struct secasvar *sav; { const struct secreplay *replay; u_int32_t diff; @@ -1728,10 +2079,10 @@ ipsec_chkreplay(seq, sa) int frlast; /* constant: last frame */ /* sanity check */ - if (sa == NULL) - printf("ipsec_chkreplay: NULL pointer was passed.\n"); + if (sav == NULL) + panic("ipsec_chkreplay: NULL pointer was passed.\n"); - replay = sa->replay; + replay = sav->replay; if (replay->wsize == 0) return 1; /* no need to check replay. */ @@ -1770,10 +2121,15 @@ ipsec_chkreplay(seq, sa) } } +/* + * check replay counter whether to update or not. + * OUT: 0: OK + * 1: NG + */ int -ipsec_updatereplay(seq, sa) +ipsec_updatereplay(seq, sav) u_int32_t seq; - struct secas *sa; + struct secasvar *sav; { struct secreplay *replay; u_int32_t diff; @@ -1782,10 +2138,10 @@ ipsec_updatereplay(seq, sa) int frlast; /* constant: last frame */ /* sanity check */ - if (sa == NULL) - printf("ipsec_chkreplay: NULL pointer was passed.\n"); + if (sav == NULL) + panic("ipsec_chkreplay: NULL pointer was passed.\n"); - replay = sa->replay; + replay = sav->replay; if (replay->wsize == 0) goto ok; /* no need to check replay. */ @@ -1796,7 +2152,7 @@ ipsec_updatereplay(seq, sa) /* sequence number of 0 is invalid */ if (seq == 0) - return 0; + return 1; /* first time */ if (replay->count == 0) { @@ -1830,13 +2186,13 @@ ipsec_updatereplay(seq, sa) /* over range to check, i.e. too old or wrapped */ if (diff >= wsizeb) - return 0; + return 1; fr = frlast - diff / 8; /* this packet already seen ? */ if ((replay->bitmap)[fr] & (1 << (diff % 8))) - return 0; + return 1; /* mark as seen */ (replay->bitmap)[fr] |= (1 << (diff % 8)); @@ -1845,14 +2201,22 @@ ipsec_updatereplay(seq, sa) } ok: - if (replay->count == ~0 - && (sa->flags & SADB_X_EXT_CYCSEQ) == 0) { - return 1; /* don't increment, no more packets accepted */ + if (replay->count == ~0) { + + /* set overflow flag */ + replay->overflow++; + + /* don't increment, no more packets accepted */ + if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) + return 1; + + ipseclog((LOG_WARNING, "replay counter made %d cycle. %s\n", + replay->overflow, ipsec_logsastr(sav))); } replay->count++; - return 1; + return 0; } /* @@ -1894,17 +2258,18 @@ ipsec4_logpacketstr(ip, spi) s = (u_int8_t *)(&ip->ip_src); d = (u_int8_t *)(&ip->ip_dst); + p = buf; snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi)); - for (p = buf; p && *p; p++) - ; + while (p && *p) + p++; snprintf(p, sizeof(buf) - (p - buf), "src=%d.%d.%d.%d", s[0], s[1], s[2], s[3]); - for (/*nothing*/; p && *p; p++) - ; + while (p && *p) + p++; snprintf(p, sizeof(buf) - (p - buf), " dst=%d.%d.%d.%d", d[0], d[1], d[2], d[3]); - for (/*nothing*/; p && *p; p++) - ; + while (p && *p) + p++; snprintf(p, sizeof(buf) - (p - buf), ")"); return buf; @@ -1919,17 +2284,18 @@ ipsec6_logpacketstr(ip6, spi) static char buf[256]; char *p; + p = buf; snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi)); - for (p = buf; p && *p; p++) - ; + while (p && *p) + p++; snprintf(p, sizeof(buf) - (p - buf), "src=%s", ip6_sprintf(&ip6->ip6_src)); - for (/*nothing*/; p && *p; p++) - ; + while (p && *p) + p++; snprintf(p, sizeof(buf) - (p - buf), " dst=%s", ip6_sprintf(&ip6->ip6_dst)); - for (/*nothing*/; p && *p; p++) - ; + while (p && *p) + p++; snprintf(p, sizeof(buf) - (p - buf), ")"); return buf; @@ -1937,36 +2303,44 @@ ipsec6_logpacketstr(ip6, spi) #endif /*INET6*/ const char * -ipsec_logsastr(sa) - struct secas *sa; +ipsec_logsastr(sav) + struct secasvar *sav; { static char buf[256]; char *p; - struct secindex *idx = &sa->saidx->idx; + struct secasindex *saidx = &sav->sah->saidx; - snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sa->spi)); - for (p = buf; p && *p; p++) - ; - if (idx->family == AF_INET) { + /* validity check */ + if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family + != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) + panic("ipsec_logsastr: family mismatched.\n"); + + p = buf; + snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); + while (p && *p) + p++; + if (((struct sockaddr *)&saidx->src)->sa_family == AF_INET) { u_int8_t *s, *d; - s = (u_int8_t *)(&idx->src); - d = (u_int8_t *)(&idx->dst); + s = (u_int8_t *)&((struct sockaddr_in *)&saidx->src)->sin_addr; + d = (u_int8_t *)&((struct sockaddr_in *)&saidx->dst)->sin_addr; snprintf(p, sizeof(buf) - (p - buf), "src=%d.%d.%d.%d dst=%d.%d.%d.%d", s[0], s[1], s[2], s[3], d[0], d[1], d[2], d[3]); } #ifdef INET6 - else if (idx->family == AF_INET6) { + else if (((struct sockaddr *)&saidx->src)->sa_family == AF_INET6) { snprintf(p, sizeof(buf) - (p - buf), - "src=%s", ip6_sprintf((struct in6_addr *)(&idx->src))); - for (/*nothing*/; p && *p; p++) - ; + "src=%s", + ip6_sprintf(&((struct sockaddr_in6 *)&saidx->src)->sin6_addr)); + while (p && *p) + p++; snprintf(p, sizeof(buf) - (p - buf), - " dst=%s", ip6_sprintf((struct in6_addr *)(&idx->dst))); + " dst=%s", + ip6_sprintf(&((struct sockaddr_in6 *)&saidx->dst)->sin6_addr)); } #endif - for (/*nothing*/; p && *p; p++) - ; + while (p && *p) + p++; snprintf(p, sizeof(buf) - (p - buf), ")"); return buf; @@ -2008,12 +2382,14 @@ ipsec4_output(state, sp, flags) { struct ip *ip = NULL; struct ipsecrequest *isr = NULL; + struct secasindex saidx; int s; int error; #ifdef IPSEC_SRCSEL struct in_ifaddr *ia; #endif struct sockaddr_in *dst4; + struct sockaddr *sa; if (!state) panic("state == NULL in ipsec4_output"); @@ -2024,8 +2400,6 @@ ipsec4_output(state, sp, flags) if (!state->dst) panic("state->dst == NULL in ipsec4_output"); - ip = mtod(state->m, struct ip *); - KEYDEBUG(KEYDEBUG_IPSEC_DATA, printf("ipsec4_output: applyed SP\n"); kdebug_secpolicy(sp)); @@ -2038,12 +2412,32 @@ ipsec4_output(state, sp, flags) * some of the IPsec operation must be performed only in * originating case. */ - if (isr->mode == IPSEC_MODE_TRANSPORT + if (isr->saidx.mode == IPSEC_MODE_TRANSPORT && (flags & IP_FORWARDING)) continue; #endif - if ((error = key_checkrequest(isr)) != 0) { + /* make SA index for search proper SA */ + ip = mtod(state->m, struct ip *); + bcopy(&isr->saidx, &saidx, sizeof(saidx)); + sa = (struct sockaddr *)&saidx.src; + if (sa->sa_len == 0) { + sa->sa_len = _SALENBYAF(AF_INET); + sa->sa_family = AF_INET; + _INPORTBYSA(&saidx.src) = IPSEC_PORT_ANY; + bcopy(&ip->ip_src, _INADDRBYSA(&saidx.src), + sizeof(ip->ip_src)); + } + sa = (struct sockaddr *)&saidx.dst; + if (sa->sa_len == 0) { + sa->sa_len = _SALENBYAF(AF_INET); + sa->sa_family = AF_INET; + _INPORTBYSA(&saidx.dst) = IPSEC_PORT_ANY; + bcopy(&ip->ip_dst, _INADDRBYSA(&saidx.dst), + sizeof(ip->ip_dst)); + } + + if ((error = key_checkrequest(isr, &saidx)) != 0) { /* * IPsec processing is required, but no SA found. * I assume that key_acquire() had been called @@ -2056,8 +2450,8 @@ ipsec4_output(state, sp, flags) } /* validity check */ - if (isr->sa == NULL) { - switch (isr->level) { + if (isr->sav == NULL) { + switch (ipsec_get_reqlevel(isr)) { case IPSEC_LEVEL_USE: continue; case IPSEC_LEVEL_REQUIRE: @@ -2066,9 +2460,15 @@ ipsec4_output(state, sp, flags) } } - if (isr->sa->state != SADB_SASTATE_MATURE - && isr->sa->state != SADB_SASTATE_DYING) { - /* If there is no valid SA, we give up to process. */ + /* + * If there is no valid SA, we give up to process any + * more. In such a case, the SA's status is changed + * from DYING to DEAD after allocating. If a packet + * send to the receiver by dead SA, the receiver can + * not decode a packet because SA has been dead. + */ + if (isr->sav->state != SADB_SASTATE_MATURE + && isr->sav->state != SADB_SASTATE_DYING) { ipsecstat.out_nosa++; error = EINVAL; goto bad; @@ -2080,55 +2480,21 @@ ipsec4_output(state, sp, flags) */ s = splsoftnet(); - if (isr->mode == IPSEC_MODE_TUNNEL && isr->proxy) { + if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { /* * build IPsec tunnel. */ /* XXX should be processed with other familiy */ - if (isr->proxy->sa_family != AF_INET) { - printf("ipsec4_output: " - "wrong proxy specified for spi=%u\n", - (u_int32_t)ntohl(isr->sa->spi)); + if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET) { + ipseclog((LOG_ERR, "ipsec4_output: " + "family mismatched between inner and outer spi=%u\n", + (u_int32_t)ntohl(isr->sav->spi))); splx(s); error = EAFNOSUPPORT; goto bad; } - /* validity check */ - if (isr->proxy->sa_family != isr->sa->proxy->sa_family - || bcmp(_INADDRBYSA(isr->proxy), - _INADDRBYSA(isr->sa->proxy), - _INALENBYAF(isr->proxy->sa_family)) != 0) { - printf("ipsec4_output: proxy address mismatch.\n"); -#ifdef IPSEC_DEBUG - printf(" SP: "); - ipsec_hexdump((caddr_t)isr->proxy, - _SALENBYAF(isr->proxy->sa_family)); - printf("\n"); - printf(" SA : "); - ipsec_hexdump((caddr_t)isr->sa->proxy, - _SALENBYAF(isr->sa->proxy->sa_family)); - printf("\n"); -#endif /* IPSEC_DEBUG */ - printf("ipsec4_output: applyed SP's proxy.\n"); - } - ip = mtod(state->m, struct ip *); -#if 0 /* XXX */ - if (!key_checktunnelsanity(isr->sa, AF_INET, - (caddr_t)&ip->ip_src, - (caddr_t)&ip->ip_dst)) { - printf("ipsec4_output: internal error: " - "ipsec packet does not match SAD/SPD: " - "%x->%x, SPI=%u\n", - (u_int32_t)ntohl(ip->ip_src.s_addr), - (u_int32_t)ntohl(ip->ip_dst.s_addr), - (u_int32_t)ntohl(isr->sa->spi)); - splx(s); - error = EINVAL; - goto bad; - } -#endif state->m = ipsec4_splithdr(state->m); if (!state->m) { @@ -2136,7 +2502,7 @@ ipsec4_output(state, sp, flags) error = ENOMEM; goto bad; } - error = ipsec4_encapsulate(state->m, isr->sa); + error = ipsec4_encapsulate(state->m, isr->sav); splx(s); if (error) { state->m = NULL; @@ -2144,7 +2510,7 @@ ipsec4_output(state, sp, flags) } ip = mtod(state->m, struct ip *); - state->ro = &isr->sa->saidx->sa_route; + state->ro = &isr->sav->sah->sa_route; state->dst = (struct sockaddr *)&state->ro->ro_dst; dst4 = (struct sockaddr_in *)state->dst; if (state->ro->ro_rt @@ -2186,7 +2552,7 @@ ipsec4_output(state, sp, flags) error = ENOMEM; goto bad; } - switch (isr->proto) { + switch (isr->saidx.proto) { case IPPROTO_ESP: #ifdef IPSEC_ESP if ((error = esp4_output(state->m, isr)) != 0) { @@ -2213,7 +2579,9 @@ ipsec4_output(state, sp, flags) } break; default: - printf("ipsec4_output: unknown ipsec protocol %d\n", isr->proto); + ipseclog((LOG_ERR, + "ipsec4_output: unknown ipsec protocol %d\n", + isr->saidx.proto)); m_freem(state->m); state->m = NULL; error = EINVAL; @@ -2250,8 +2618,10 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) { struct ip6_hdr *ip6; struct ipsecrequest *isr = NULL; + struct secasindex saidx; int error = 0; int plen; + struct sockaddr *sa; if (!state) panic("state == NULL in ipsec6_output"); @@ -2267,17 +2637,37 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) panic("tun == NULL in ipsec6_output"); KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec6_output: applyed SP\n"); + printf("ipsec6_output_trans: applyed SP\n"); kdebug_secpolicy(sp)); *tun = 0; for (isr = sp->req; isr; isr = isr->next) { - if (isr->mode == IPSEC_MODE_TUNNEL) { + if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { /* the rest will be handled by ipsec6_output_tunnel() */ break; } - if (key_checkrequest(isr) == ENOENT) { + /* make SA index for search proper SA */ + ip6 = mtod(state->m, struct ip6_hdr *); + bcopy(&isr->saidx, &saidx, sizeof(saidx)); + sa = (struct sockaddr *)&saidx.src; + if (sa->sa_len == 0) { + sa->sa_len = _SALENBYAF(AF_INET6); + sa->sa_family = AF_INET6; + _INPORTBYSA(&saidx.src) = IPSEC_PORT_ANY; + bcopy(&ip6->ip6_src, _INADDRBYSA(&saidx.src), + sizeof(ip6->ip6_src)); + } + sa = (struct sockaddr *)&saidx.dst; + if (sa->sa_len == 0) { + sa->sa_len = _SALENBYAF(AF_INET6); + sa->sa_family = AF_INET6; + _INPORTBYSA(&saidx.dst) = IPSEC_PORT_ANY; + bcopy(&ip6->ip6_dst, _INADDRBYSA(&saidx.dst), + sizeof(ip6->ip6_dst)); + } + + if (key_checkrequest(isr, &saidx) == ENOENT) { /* * IPsec processing is required, but no SA found. * I assume that key_acquire() had been called @@ -2291,25 +2681,28 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) } /* validity check */ - if (isr->sa == NULL) { - switch (isr->level) { + if (isr->sav == NULL) { + switch (ipsec_get_reqlevel(isr)) { case IPSEC_LEVEL_USE: continue; case IPSEC_LEVEL_REQUIRE: /* must be not reached here. */ - panic("ipsec6_output: no SA found, but required."); + panic("ipsec6_output_trans: no SA found, but required."); } } - if (isr->sa->state != SADB_SASTATE_MATURE - && isr->sa->state != SADB_SASTATE_DYING) { - /* If there is no valid SA, we give up to process. */ + /* + * If there is no valid SA, we give up to process. + * see same place at ipsec4_output(). + */ + if (isr->sav->state != SADB_SASTATE_MATURE + && isr->sav->state != SADB_SASTATE_DYING) { ipsec6stat.out_nosa++; error = EINVAL; goto bad; } - switch (isr->proto) { + switch (isr->saidx.proto) { case IPPROTO_ESP: #ifdef IPSEC_ESP error = esp6_output(state->m, nexthdrp, mprev->m_next, isr); @@ -2325,8 +2718,10 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) error = ipcomp6_output(state->m, nexthdrp, mprev->m_next, isr); break; default: - printf("ipsec6_output_trans: unknown ipsec protocol %d\n", isr->proto); + ipseclog((LOG_ERR, "ipsec6_output_trans: " + "unknown ipsec protocol %d\n", isr->saidx.proto)); m_freem(state->m); + ipsec6stat.out_inval++; error = EINVAL; break; } @@ -2336,7 +2731,8 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) } plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr); if (plen > IPV6_MAXPACKET) { - printf("ipsec6_output: IPsec with IPv6 jumbogram is not supported\n"); + ipseclog((LOG_ERR, "ipsec6_output_trans: " + "IPsec with IPv6 jumbogram is not supported\n")); ipsec6stat.out_inval++; error = EINVAL; /*XXX*/ goto bad; @@ -2368,6 +2764,7 @@ ipsec6_output_tunnel(state, sp, flags) { struct ip6_hdr *ip6; struct ipsecrequest *isr = NULL; + struct secasindex saidx; int error = 0; int plen; #ifdef IPSEC_SRCSEL @@ -2392,12 +2789,14 @@ ipsec6_output_tunnel(state, sp, flags) * processed by ipsec6_output_trans(). */ for (isr = sp->req; isr; isr = isr->next) { - if (isr->mode == IPSEC_MODE_TUNNEL) + if (isr->saidx.mode == IPSEC_MODE_TUNNEL) break; } for (/*already initialized*/; isr; isr = isr->next) { - if (key_checkrequest(isr) == ENOENT) { + /* When tunnel mode, SA peers must be specified. */ + bcopy(&isr->saidx, &saidx, sizeof(saidx)); + if (key_checkrequest(isr, &saidx) == ENOENT) { /* * IPsec processing is required, but no SA found. * I assume that key_acquire() had been called @@ -2411,8 +2810,8 @@ ipsec6_output_tunnel(state, sp, flags) } /* validity check */ - if (isr->sa == NULL) { - switch (isr->level) { + if (isr->sav == NULL) { + switch (ipsec_get_reqlevel(isr)) { case IPSEC_LEVEL_USE: continue; case IPSEC_LEVEL_REQUIRE: @@ -2421,9 +2820,12 @@ ipsec6_output_tunnel(state, sp, flags) } } - if (isr->sa->state != SADB_SASTATE_MATURE - && isr->sa->state != SADB_SASTATE_DYING) { - /* If there is no valid SA, we give up to process. */ + /* + * If there is no valid SA, we give up to process. + * see same place at ipsec4_output(). + */ + if (isr->sav->state != SADB_SASTATE_MATURE + && isr->sav->state != SADB_SASTATE_DYING) { ipsec6stat.out_nosa++; error = EINVAL; goto bad; @@ -2435,61 +2837,31 @@ ipsec6_output_tunnel(state, sp, flags) */ s = splsoftnet(); - if (isr->mode == IPSEC_MODE_TUNNEL && isr->proxy) { + if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { /* * build IPsec tunnel. */ /* XXX should be processed with other familiy */ - if (isr->proxy->sa_family != AF_INET6) { - printf("ipsec6_output_tunnel: " - "wrong proxy specified for spi=%u\n", - (u_int32_t)ntohl(isr->sa->spi)); + if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET6) { + ipseclog((LOG_ERR, "ipsec6_output_tunnel: " + "family mismatched between inner and outer, spi=%u\n", + (u_int32_t)ntohl(isr->sav->spi))); splx(s); + ipsec6stat.out_inval++; error = EAFNOSUPPORT; goto bad; } - /* validity check */ - if (isr->proxy->sa_family != isr->sa->proxy->sa_family - || bcmp(_INADDRBYSA(isr->proxy), - _INADDRBYSA(isr->sa->proxy), - _INALENBYAF(isr->proxy->sa_family)) != 0) { - printf("ipsec6_output_tunnel: proxy address mismatch.\n"); -#ifdef IPSEC_DEBUG - printf(" SP: "); - ipsec_hexdump((caddr_t)isr->proxy, - _SALENBYAF(isr->proxy->sa_family)); - printf("\n"); - printf(" SA : "); - ipsec_hexdump((caddr_t)isr->sa->proxy, - _SALENBYAF(isr->sa->proxy->sa_family)); - printf("\n"); -#endif /* IPSEC_DEBUG */ - printf("ipsec6_output_tunnel: applyed SP's proxy.\n"); - } - ip6 = mtod(state->m, struct ip6_hdr *); -#if 0 /* XXX */ - if (!key_checktunnelsanity(isr->sa, AF_INET6, - (caddr_t)&ip6->ip6_src, - (caddr_t)&ip6->ip6_dst)) { - printf("ipsec6_output_tunnel: internal error: " - "ipsec packet does not match SAD/SPD: " - "SPI=%u\n", - (u_int32_t)ntohl(isr->sa->spi)); - splx(s); - error = EINVAL; - goto bad; - } -#endif state->m = ipsec6_splithdr(state->m); if (!state->m) { splx(s); + ipsec6stat.out_nomem++; error = ENOMEM; goto bad; } - error = ipsec6_encapsulate(state->m, isr->sa); + error = ipsec6_encapsulate(state->m, isr->sav); splx(s); if (error) { state->m = 0; @@ -2497,7 +2869,7 @@ ipsec6_output_tunnel(state, sp, flags) } ip6 = mtod(state->m, struct ip6_hdr *); - state->ro = &isr->sa->saidx->sa_route; + state->ro = &isr->sav->sah->sa_route; state->dst = (struct sockaddr *)&state->ro->ro_dst; dst6 = (struct sockaddr_in6 *)state->dst; if (state->ro->ro_rt @@ -2515,6 +2887,7 @@ ipsec6_output_tunnel(state, sp, flags) } if (state->ro->ro_rt == 0) { ip6stat.ip6s_noroute++; + ipsec6stat.out_noroute++; error = EHOSTUNREACH; goto bad; } @@ -2524,12 +2897,20 @@ ipsec6_output_tunnel(state, sp, flags) dst6 = (struct sockaddr_in6 *)state->dst; } #endif -#ifdef IPSEC_SELSRC +#ifdef IPSEC_SRCSEL + /* + * Which address in SA or in routing table should I + * select from ? But I had set from SA at + * ipsec6_encapsulate(). + */ ia6 = in6_selectsrc(dst6, NULL, NULL, (struct route_in6 *)state->ro, NULL, &error); - if (ia6 == NULL) + if (ia6 == NULL) { + ip6stat.ip6s_noroute++; + ipsec6stat.out_noroute++; goto bad; + } ip6->ip6_src = *ia6; #endif } else @@ -2537,11 +2918,12 @@ ipsec6_output_tunnel(state, sp, flags) state->m = ipsec6_splithdr(state->m); if (!state->m) { + ipsec6stat.out_nomem++; error = ENOMEM; goto bad; } ip6 = mtod(state->m, struct ip6_hdr *); - switch (isr->proto) { + switch (isr->saidx.proto) { case IPPROTO_ESP: #ifdef IPSEC_ESP error = esp6_output(state->m, &ip6->ip6_nxt, state->m->m_next, isr); @@ -2557,8 +2939,10 @@ ipsec6_output_tunnel(state, sp, flags) /* XXX code should be here */ /*FALLTHROUGH*/ default: - printf("ipsec6_output_tunnel: unknown ipsec protocol %d\n", isr->proto); + ipseclog((LOG_ERR, "ipsec6_output_tunnel: " + "unknown ipsec protocol %d\n", isr->saidx.proto)); m_freem(state->m); + ipsec6stat.out_inval++; error = EINVAL; break; } @@ -2568,7 +2952,8 @@ ipsec6_output_tunnel(state, sp, flags) } plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr); if (plen > IPV6_MAXPACKET) { - printf("ipsec6_output_tunnel: IPsec with IPv6 jumbogram is not supported\n"); + ipseclog((LOG_ERR, "ipsec6_output_tunnel: " + "IPsec with IPv6 jumbogram is not supported\n")); ipsec6stat.out_inval++; error = EINVAL; /*XXX*/ goto bad; @@ -2667,10 +3052,10 @@ ipsec6_splithdr(m) /* validate inbound IPsec tunnel packet. */ int -ipsec4_tunnel_validate(ip, nxt0, sa) +ipsec4_tunnel_validate(ip, nxt0, sav) struct ip *ip; u_int nxt0; - struct secas *sa; + struct secasvar *sav; { u_int8_t nxt = nxt0 & 0xff; struct sockaddr_in *sin; @@ -2685,11 +3070,9 @@ ipsec4_tunnel_validate(ip, nxt0, sa) #endif if (hlen != sizeof(struct ip)) return 0; - if (sa->proxy == NULL) - return 0; - switch (sa->proxy->sa_family) { + switch (((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) { case AF_INET: - sin = (struct sockaddr_in *)sa->proxy; + sin = (struct sockaddr_in *)&sav->sah->saidx.dst; if (bcmp(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst)) != 0) return 0; break; @@ -2708,21 +3091,19 @@ ipsec4_tunnel_validate(ip, nxt0, sa) #ifdef INET6 /* validate inbound IPsec tunnel packet. */ int -ipsec6_tunnel_validate(ip6, nxt0, sa) +ipsec6_tunnel_validate(ip6, nxt0, sav) struct ip6_hdr *ip6; u_int nxt0; - struct secas *sa; + struct secasvar *sav; { u_int8_t nxt = nxt0 & 0xff; struct sockaddr_in6 *sin6; if (nxt != IPPROTO_IPV6) return 0; - if (sa->proxy == NULL) - return 0; - switch (sa->proxy->sa_family) { + switch (((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) { case AF_INET6: - sin6 = (struct sockaddr_in6 *)sa->proxy; + sin6 = ((struct sockaddr_in6 *)&sav->sah->saidx.dst); if (!IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6->sin6_addr)) return 0; break; @@ -2757,8 +3138,7 @@ ipsec_copypkt(m) * to the cluster. * XXX: is this approach effective? */ - if (n->m_ext.ext_free || MCLISREFERENCED(n)) - { + if (n->m_ext.ext_free || MCLISREFERENCED(n)) { int remain, copied; struct mbuf *mm; @@ -2840,8 +3220,6 @@ ipsec_copypkt(m) return(NULL); } - - /* * System control for IPSEC */ @@ -2929,6 +3307,8 @@ ipsec_sysctl(name, namelen, oldp, oldlenp, newp, newlen) &ip4_ipsec_dfbit); case IPSECCTL_ECN: return sysctl_int(oldp, oldlenp, newp, newlen, &ip4_ipsec_ecn); + case IPSECCTL_DEBUG: + return sysctl_int(oldp, oldlenp, newp, newlen, &ipsec_debug); default: return EOPNOTSUPP; } @@ -3014,6 +3394,8 @@ ipsec6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) &ip6_inbound_call_ike); case IPSECCTL_ECN: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_ipsec_ecn); + case IPSECCTL_DEBUG: + return sysctl_int(oldp, oldlenp, newp, newlen, &ipsec_debug); default: return EOPNOTSUPP; } diff --git a/sys/netinet6/ipsec.h b/sys/netinet6/ipsec.h index 0d11e1c04a57..da73b7604192 100644 --- a/sys/netinet6/ipsec.h +++ b/sys/netinet6/ipsec.h @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec.h,v 1.8 2000/01/06 15:46:10 itojun Exp $ */ +/* $NetBSD: ipsec.h,v 1.9 2000/01/31 14:19:06 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -45,16 +45,35 @@ #ifdef _KERNEL +/* + * Security Policy Index + * NOTE: Encure to be same address family and upper layer protocol. + * NOTE: ul_proto, port number, uid, gid: + * ANY: reserved for waldcard. + * 0 to (~0 - 1): is one of the number of each value. + */ +struct secpolicyindex { + u_int8_t dir; /* direction of packet flow, see blow */ + struct sockaddr_storage src; /* IP src address for SP */ + struct sockaddr_storage dst; /* IP dst address for SP */ + u_int8_t prefs; /* prefix length in bits for src */ + u_int8_t prefd; /* prefix length in bits for dst */ + u_int16_t ul_proto; /* upper layer Protocol */ +#ifdef notyet + uid_t uids; + uid_t uidd; + gid_t gids; + gid_t gidd; +#endif +}; + /* Security Policy Data Base */ struct secpolicy { - struct secpolicy *next; - struct secpolicy *prev; - struct keytree *spt; /* back pointer to the top of SPD */ + LIST_ENTRY(secpolicy) chain; - struct secindex idx; /* index */ - - int refcnt; /* reference count */ - u_int state; /* 0: dead, others: alive */ + int refcnt; /* reference count */ + struct secpolicyindex spidx; /* selector */ + u_int state; /* 0: dead, others: alive */ #define IPSEC_SPSTATE_DEAD 0 #define IPSEC_SPSTATE_ALIVE 1 @@ -68,22 +87,44 @@ struct secpolicy { struct ipsecrequest { struct ipsecrequest *next; /* pointer to next structure */ - /* If 0, it means end of chain. */ - - u_int proto; /* IPPROTO_ESP or IPPROTO_AH */ - u_int mode; /* mode for security protocol, see below. */ + /* If NULL, it means the end of chain. */ + struct secasindex saidx;/* hint for search proper SA */ + /* if __ss_len == 0 then no address specified.*/ u_int level; /* IPsec level defined below. */ - struct sockaddr *proxy; /* Destination address in Outer IP header. */ - /* If mode == TRANSPORT, it must be set NULL. */ - struct secas *sa; /* place holder for the security association */ + struct secasvar *sav; /* place holder of SA for use */ struct secpolicy *sp; /* back pointer to SP */ }; +/* security policy in PCB */ +struct inpcbpolicy { + struct secpolicy *sp_in; + struct secpolicy *sp_out; + int priv; /* privileged socket ? */ +}; #endif /*_KERNEL*/ -#define IPSEC_MODE_TRANSPORT 0 -#define IPSEC_MODE_TUNNEL 1 +/* according to IANA assignment, port 0x0000 and proto 0xff are reserved. */ +#define IPSEC_PORT_ANY 0 +#define IPSEC_ULPROTO_ANY 255 +#define IPSEC_PROTO_ANY 255 + +/* mode of security protocol */ +/* NOTE: DON'T use IPSEC_MODE_ANY at SPD. It's only use in SAD */ +#define IPSEC_MODE_ANY 0 /* i.e. wildcard. */ +#define IPSEC_MODE_TRANSPORT 1 +#define IPSEC_MODE_TUNNEL 2 + +/* + * Direction of security policy. + * NOTE: Since INVALID is used just as flag. + * The other are used for loop counter too. + */ +#define IPSEC_DIR_ANY 0 +#define IPSEC_DIR_INBOUND 1 +#define IPSEC_DIR_OUTBOUND 2 +#define IPSEC_DIR_MAX 3 +#define IPSEC_DIR_INVALID 4 /* Policy level */ /* @@ -101,15 +142,29 @@ struct ipsecrequest { #define IPSEC_LEVEL_DEFAULT 0 /* reference to system default */ #define IPSEC_LEVEL_USE 1 /* use SA if present. */ #define IPSEC_LEVEL_REQUIRE 2 /* require SA. */ +#define IPSEC_LEVEL_UNIQUE 3 /* unique SA. */ +#define IPSEC_MANUAL_REQID_MAX 0x3fff + /* + * if security policy level == unique, this id + * indicate to a relative SA for use, else is + * zero. + * 1 - 0x3fff are reserved for manual keying. + * 0 are reserved for above reason. Others is + * for kernel use. + * Note that this id doesn't identify SA + * by only itself. + */ #define IPSEC_REPLAYWSIZE 32 /* statistics for ipsec processing */ struct ipsecstat { - u_quad_t in_success; /* succeeded inbound process */ - u_quad_t in_polvio; /* security policy violation for inbound process */ - u_quad_t in_nosa; /* inbound SA is unavailable */ - u_quad_t in_inval; /* inbound processing failed due to EINVAL */ + u_quad_t in_success; /* succeeded inbound process */ + u_quad_t in_polvio; + /* security policy violation for inbound process */ + u_quad_t in_nosa; /* inbound SA is unavailable */ + u_quad_t in_inval; /* inbound processing failed due to EINVAL */ + u_quad_t in_nomem; /* inbound processing failed due to ENOBUFS */ u_quad_t in_badspi; /* failed getting a SPI */ u_quad_t in_ahreplay; /* AH replay check failed */ u_quad_t in_espreplay; /* ESP replay check failed */ @@ -117,15 +172,19 @@ struct ipsecstat { u_quad_t in_ahauthfail; /* AH authentication failure */ u_quad_t in_espauthsucc; /* ESP authentication success */ u_quad_t in_espauthfail; /* ESP authentication failure */ - u_quad_t in_esphist[SADB_EALG_MAX]; - u_quad_t in_ahhist[SADB_AALG_MAX]; + u_quad_t in_esphist[256]; + u_quad_t in_ahhist[256]; + u_quad_t in_comphist[256]; u_quad_t out_success; /* succeeded outbound process */ - u_quad_t out_polvio; /* security policy violation for outbound process */ + u_quad_t out_polvio; + /* security policy violation for outbound process */ u_quad_t out_nosa; /* outbound SA is unavailable */ u_quad_t out_inval; /* outbound process failed due to EINVAL */ + u_quad_t out_nomem; /* inbound processing failed due to ENOBUFS */ u_quad_t out_noroute; /* there is no route */ - u_quad_t out_esphist[SADB_EALG_MAX]; - u_quad_t out_ahhist[SADB_AALG_MAX]; + u_quad_t out_esphist[256]; + u_quad_t out_ahhist[256]; + u_quad_t out_comphist[256]; }; /* @@ -145,7 +204,8 @@ struct ipsecstat { #define IPSECCTL_AH_OFFSETMASK 9 #define IPSECCTL_DFBIT 10 #define IPSECCTL_ECN 11 -#define IPSECCTL_MAXID 12 +#define IPSECCTL_DEBUG 12 +#define IPSECCTL_MAXID 13 #define IPSECCTL_NAMES { \ { 0, 0 }, \ @@ -160,6 +220,7 @@ struct ipsecstat { { "ah_offsetmask", CTLTYPE_INT }, \ { "dfbit", CTLTYPE_INT }, \ { "ecn", CTLTYPE_INT }, \ + { "debug", CTLTYPE_INT }, \ } #define IPSEC6CTL_NAMES { \ @@ -175,6 +236,7 @@ struct ipsecstat { { 0, 0 }, \ { 0, 0 }, \ { "ecn", CTLTYPE_INT }, \ + { "debug", CTLTYPE_INT }, \ } #define IPSECCTL_VARS { \ @@ -190,6 +252,7 @@ struct ipsecstat { &ip4_ah_offsetmask, \ &ip4_ipsec_dfbit, \ &ip4_ipsec_ecn, \ + &ipsec_debug, \ } #define IPSEC6CTL_VARS { \ @@ -205,6 +268,7 @@ struct ipsecstat { 0, \ 0, \ &ip6_ipsec_ecn, \ + &ipsec_debug, \ } #ifdef _KERNEL @@ -214,6 +278,9 @@ struct ipsec_output_state { struct sockaddr *dst; }; +extern int ipsec_debug; + +#ifdef INET extern struct ipsecstat ipsecstat; extern struct secpolicy ip4_def_policy; extern int ip4_esp_trans_deflev; @@ -225,6 +292,7 @@ extern int ip4_ah_cleartos; extern int ip4_ah_offsetmask; extern int ip4_ipsec_dfbit; extern int ip4_ipsec_ecn; +#endif #ifdef INET6 extern struct ipsecstat ipsec6stat; @@ -237,54 +305,61 @@ extern int ip6_inbound_call_ike; extern int ip6_ipsec_ecn; #endif +#define ipseclog(x) do { if (ipsec_debug) log x; } while (0) + extern struct secpolicy *ipsec4_getpolicybysock - __P((struct mbuf *, struct socket *, int *)); + __P((struct mbuf *, u_int, struct socket *, int *)); extern struct secpolicy *ipsec4_getpolicybyaddr - __P((struct mbuf *, int, int *)); + __P((struct mbuf *, u_int, int, int *)); #ifdef INET6 extern struct secpolicy *ipsec6_getpolicybysock - __P((struct mbuf *, struct socket *, int *)); + __P((struct mbuf *, u_int, struct socket *, int *)); extern struct secpolicy *ipsec6_getpolicybyaddr - __P((struct mbuf *, int, int *)); + __P((struct mbuf *, u_int, int, int *)); #endif /*INET6*/ struct inpcb; #ifdef INET6 struct in6pcb; #endif -extern int ipsec_init_policy __P((struct secpolicy **)); -extern struct secpolicy *ipsec_copy_policy __P((struct secpolicy *)); -extern int ipsec_set_policy __P((struct secpolicy **, int, caddr_t, int, int)); -extern int ipsec_get_policy __P((struct secpolicy *, struct mbuf **)); -extern int ipsec4_delete_pcbpolicy __P((struct inpcb *)); -#ifdef INET6 -extern int ipsec6_delete_pcbpolicy __P((struct in6pcb *)); -#endif +extern int ipsec_init_policy __P((struct socket *so, struct inpcbpolicy **)); +extern int ipsec_copy_policy + __P((struct inpcbpolicy *, struct inpcbpolicy *)); extern u_int ipsec_get_reqlevel __P((struct ipsecrequest *)); +extern int ipsec4_set_policy __P((struct inpcb *inp, int optname, + caddr_t request, size_t len, int priv)); +extern int ipsec4_get_policy __P((struct inpcb *inpcb, caddr_t request, + size_t len, struct mbuf **mp)); +extern int ipsec4_delete_pcbpolicy __P((struct inpcb *)); extern int ipsec4_in_reject_so __P((struct mbuf *, struct socket *)); extern int ipsec4_in_reject __P((struct mbuf *, struct inpcb *)); #ifdef INET6 extern int ipsec6_in_reject_so __P((struct mbuf *, struct socket *)); +extern int ipsec6_delete_pcbpolicy __P((struct in6pcb *)); +extern int ipsec6_set_policy __P((struct in6pcb *in6p, int optname, + caddr_t request, size_t len, int priv)); +extern int ipsec6_get_policy __P((struct in6pcb *in6p, caddr_t request, + size_t len, struct mbuf **mp)); extern int ipsec6_in_reject __P((struct mbuf *, struct in6pcb *)); #endif /*INET6*/ struct secas; struct tcpcb; struct tcp6cb; -extern int ipsec_chkreplay __P((u_int32_t, struct secas *)); -extern int ipsec_updatereplay __P((u_int32_t, struct secas *)); +extern int ipsec_chkreplay __P((u_int32_t, struct secasvar *)); +extern int ipsec_updatereplay __P((u_int32_t, struct secasvar *)); -extern size_t ipsec4_hdrsiz __P((struct mbuf *, struct inpcb *)); +extern size_t ipsec4_hdrsiz __P((struct mbuf *, u_int, struct inpcb *)); extern size_t ipsec4_hdrsiz_tcp __P((struct tcpcb *)); #ifdef INET6 -extern size_t ipsec6_hdrsiz __P((struct mbuf *, struct in6pcb *)); -#ifdef TCP6 -extern size_t ipsec6_hdrsiz_tcp __P((struct tcp6cb *)); -#else +extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct in6pcb *)); +#ifndef TCP6 extern size_t ipsec6_hdrsiz_tcp __P((struct tcpcb *)); +#else +extern size_t ipsec6_hdrsiz_tcp __P((struct tcp6cb *)); #endif #endif @@ -296,7 +371,7 @@ extern const char *ipsec4_logpacketstr __P((struct ip *, u_int32_t)); #ifdef INET6 extern const char *ipsec6_logpacketstr __P((struct ip6_hdr *, u_int32_t)); #endif -extern const char *ipsec_logsastr __P((struct secas *)); +extern const char *ipsec_logsastr __P((struct secasvar *)); extern void ipsec_dumpmbuf __P((struct mbuf *)); @@ -308,10 +383,10 @@ extern int ipsec6_output_trans __P((struct ipsec_output_state *, u_char *, extern int ipsec6_output_tunnel __P((struct ipsec_output_state *, struct secpolicy *, int)); #endif -extern int ipsec4_tunnel_validate __P((struct ip *, u_int, struct secas *)); +extern int ipsec4_tunnel_validate __P((struct ip *, u_int, struct secasvar *)); #ifdef INET6 extern int ipsec6_tunnel_validate __P((struct ip6_hdr *, u_int, - struct secas *)); + struct secasvar *)); #endif extern struct mbuf *ipsec_copypkt __P((struct mbuf *)); @@ -321,11 +396,11 @@ extern int ipsec6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); #endif /*_KERNEL*/ #ifndef _KERNEL -extern int ipsec_get_policylen(char *reqstr); -extern int ipsec_set_policy(char *buf, int len, char *reqstr); -extern char *ipsec_dump_policy(char *buf, char *delimiter); +extern caddr_t ipsec_set_policy __P((char *, int)); +extern int ipsec_get_policylen __P((caddr_t)); +extern char *ipsec_dump_policy __P((caddr_t, char *)); -extern char *ipsec_strerror(void); +extern char *ipsec_strerror __P((void)); #endif /*!_KERNEL*/ #endif /*_NETINET6_IPSEC_H_*/ diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index a4a955d1f664..3e1953472b27 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -1,4 +1,4 @@ -/* $NetBSD: raw_ip6.c,v 1.15 2000/01/06 15:46:11 itojun Exp $ */ +/* $NetBSD: raw_ip6.c,v 1.16 2000/01/31 14:19:06 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -513,7 +513,7 @@ rip6_usrreq(so, req, m, nam, control, p) in6p->in6p_ip6.ip6_nxt = (long)nam; in6p->in6p_cksum = -1; #ifdef IPSEC - error = ipsec_init_policy(&in6p->in6p_sp); + error = ipsec_init_policy(so, &in6p->in6p_sp); if (error != 0) { in6_pcbdetach(in6p); break; diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 973e9e13f5c4..cb32589782bf 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: udp6_usrreq.c,v 1.18 2000/01/31 10:39:27 itojun Exp $ */ +/* $NetBSD: udp6_usrreq.c,v 1.19 2000/01/31 14:19:07 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -825,7 +825,7 @@ udp6_usrreq(so, req, m, addr6, control, p) in6p = sotoin6pcb(so); in6p->in6p_cksum = -1; /* just to be sure */ #ifdef IPSEC - error = ipsec_init_policy(&in6p->in6p_sp); + error = ipsec_init_policy(so, &in6p->in6p_sp); if (error != 0) { in6_pcbdetach(in6p); break; diff --git a/sys/netkey/key.c b/sys/netkey/key.c index 8d3914134378..7ed84e747f9f 100644 --- a/sys/netkey/key.c +++ b/sys/netkey/key.c @@ -1,4 +1,4 @@ -/* $NetBSD: key.c,v 1.11 1999/09/07 07:41:45 itojun Exp $ */ +/* $NetBSD: key.c,v 1.12 2000/01/31 14:19:09 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,25 +29,18 @@ * SUCH DAMAGE. */ -/* KAME Id: key.c,v 1.1.6.5.2.20 1999/07/31 08:34:27 itojun Exp */ +/* KAME Id: key.c,v 1.62 2000/01/29 06:21:00 itojun Exp */ /* - * This code is referd to RFC 2367, - * and was consulted with NRL's netkey/osdep_44bsd.c. + * This code is referd to RFC 2367 */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #include "opt_inet.h" -#ifdef __NetBSD__ #include "opt_ipsec.h" -#endif -#endif -#ifdef __NetBSD__ -# ifdef _KERNEL -# define KERNEL -# endif -#endif +/* this is for backward compatibility. we should not touch those. */ +#define ss_len __ss_len +#define ss_family __ss_family #include #include @@ -59,11 +52,9 @@ #include #include #include -#ifdef __FreeBSD__ -#include -#endif #include #include +#include #include #include @@ -73,12 +64,20 @@ #include #include #include -#include #ifdef INET6 #include #include +#include +#endif /* INET6 */ + +#ifdef INET +#include +#endif +#ifdef INET6 +#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) #include +#endif #endif /* INET6 */ #include @@ -94,9 +93,18 @@ #endif #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -MALLOC_DEFINE(M_SECA, "key mgmt", "security associations, key management"); -#endif +#include + +/* + * Note on SA reference counting: + * - SAs that are not in DEAD state will have (total external reference + 1) + * following value in reference count field. they cannot be freed and are + * referenced from SA header. + * - SAs that are in DEAD state will have (total external reference) + * in reference count field. they are ready to be freed. reference from + * SA header will be removed in key_delsav(), when the reference count + * field hits 0 (= no external reference other than from SA header. + */ #if defined(IPSEC_DEBUG) u_int32_t key_debug_level = 0; @@ -112,274 +120,226 @@ static int key_blockacq_lifetime = 20; /* lifetime for blocking SADB_ACQUIRE.*/ static u_int32_t acq_seq = 0; static int key_tick_init_random = 0; -#ifdef RESTRICTED_DIR -static struct keytree sptree[SADB_X_DIR_MAX]; /* SPD */ -static struct keytree saidxtree[SADB_X_DIR_MAX]; /* SADB */ -static struct keytree regtree[SADB_SATYPE_MAX + 1]; -#else -static struct keytree sptree; /* SPD */ -static struct keytree saidxtree; /* SADB */ -static struct keytree regtree[SADB_SATYPE_MAX + 1]; -#endif +static LIST_HEAD(_sptree, secpolicy) sptree[IPSEC_DIR_MAX]; /* SPD */ +static LIST_HEAD(_sahtree, secashead) sahtree; /* SAD */ +static LIST_HEAD(_regtree, secreg) regtree[SADB_SATYPE_MAX + 1]; + /* registed list */ #ifndef IPSEC_NONBLOCK_ACQUIRE -static struct keytree acqtree; +static LIST_HEAD(_acqtree, secacq) acqtree; /* acquiring list */ #endif + struct key_cb key_cb; /* search order for SAs */ static u_int saorder_state_valid[] = { - SADB_SASTATE_MATURE, SADB_SASTATE_DYING + SADB_SASTATE_DYING, SADB_SASTATE_MATURE, + /* + * This order is important because we must select a oldest SA + * for outbound processing. For inbound, This is not important. + */ }; static u_int saorder_state_alive[] = { + /* except DEAD */ SADB_SASTATE_MATURE, SADB_SASTATE_DYING, SADB_SASTATE_LARVAL }; static u_int saorder_state_any[] = { SADB_SASTATE_MATURE, SADB_SASTATE_DYING, SADB_SASTATE_LARVAL, SADB_SASTATE_DEAD }; -#ifdef RESTRICTED_DIR -static u_int saorder_dir_output[] = { - SADB_X_DIR_OUTBOUND, SADB_X_DIR_BIDIRECT -}; -static u_int saorder_dir_input[] = { - SADB_X_DIR_INBOUND, SADB_X_DIR_BIDIRECT -}; -static u_int saorder_dir_any[] = { - SADB_X_DIR_OUTBOUND, SADB_X_DIR_INBOUND, SADB_X_DIR_BIDIRECT -}; + + +#ifndef LIST_FOREACH +#define LIST_FOREACH(elm, head, field) \ + for (elm = LIST_FIRST(head); elm; elm = LIST_NEXT(elm, field)) #endif +#define __LIST_CHAINED(elm) \ + (!((elm)->chain.le_next == NULL && (elm)->chain.le_prev == NULL)) +#define LIST_INSERT_TAIL(head, elm, type, field) \ +do {\ + struct type *curelm = LIST_FIRST(head); \ + if (curelm == NULL) {\ + LIST_INSERT_HEAD(head, elm, field); \ + } else { \ + while (LIST_NEXT(curelm, field)) \ + curelm = LIST_NEXT(curelm, field);\ + LIST_INSERT_AFTER(curelm, elm, field);\ + }\ +} while (0) -#ifdef __FreeBSD__ -#if defined(IPSEC_DEBUG) -SYSCTL_INT(_net_key, KEYCTL_DEBUG_LEVEL, debug, CTLFLAG_RW, \ - &key_debug_level, 0, ""); -#endif /* defined(IPSEC_DEBUG) */ +#define KEY_CHKSASTATE(head, sav, name) \ +do { \ + if ((head) != (sav)) { \ + printf("%s: state mismatched (TREE=%d SA=%d)\n", \ + (name), (head), (sav)); \ + continue; \ + } \ +} while (0) -/* max count of trial for the decision of spi value */ -SYSCTL_INT(_net_key, KEYCTL_SPI_TRY, spi_trycnt, CTLFLAG_RW, \ - &key_spi_trycnt, 0, ""); - -/* minimum spi value to allocate automatically. */ -SYSCTL_INT(_net_key, KEYCTL_SPI_MIN_VALUE, spi_minval, CTLFLAG_RW, \ - &key_spi_minval, 0, ""); - -/* maximun spi value to allocate automatically. */ -SYSCTL_INT(_net_key, KEYCTL_SPI_MAX_VALUE, spi_maxval, CTLFLAG_RW, \ - &key_spi_maxval, 0, ""); - -/* interval to initialize randseed */ -SYSCTL_INT(_net_key, KEYCTL_RANDOM_INT, int_random, CTLFLAG_RW, \ - &key_int_random, 0, ""); - -/* lifetime for larval SA */ -SYSCTL_INT(_net_key, KEYCTL_LARVAL_LIFETIME, larval_lifetime, CTLFLAG_RW, \ - &key_larval_lifetime, 0, ""); - -/* counter for blocking to send SADB_ACQUIRE to IKEd */ -SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \ - &key_blockacq_count, 0, ""); - -/* lifetime for blocking to send SADB_ACQUIRE to IKEd */ -SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ - &key_blockacq_lifetime, 0, ""); - -#endif /* __FreeBSD__ */ - -#if (defined(__bsdi__) && !defined(ALTQ)) || defined(__NetBSD__) -typedef void (timeout_t)(void *); -#endif +#define KEY_CHKSPDIR(head, sp, name) \ +do { \ + if ((head) != (sp)) { \ + printf("%s: direction mismatched (TREE=%d SP=%d), " \ + "anyway continue.\n", \ + (name), (head), (sp)); \ + } \ +} while (0) #if 1 -#define KMALLOC(p, t, n) \ +#define KMALLOC(p, t, n) \ ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT)) -#define KFREE(p) \ +#define KFREE(p) \ free((caddr_t)(p), M_SECA); #else #define KMALLOC(p, t, n) \ - do { \ - ((p) = (t)malloc((unsigned long)(n), M_SECA, M_NOWAIT));\ - printf("%s %d: %p <- KMALLOC(%s, %d)\n", \ - __FILE__, __LINE__, (p), #t, n); \ - } while (0) +do { \ + ((p) = (t)malloc((unsigned long)(n), M_SECA, M_NOWAIT)); \ + printf("%s %d: %p <- KMALLOC(%s, %d)\n", \ + __FILE__, __LINE__, (p), #t, n); \ +} while (0) -#define KFREE(p) \ - do { \ - printf("%s %d: %p -> KFREE()\n", __FILE__, __LINE__, (p));\ - free((caddr_t)(p), M_SECA); \ +#define KFREE(p) \ + do { \ + printf("%s %d: %p -> KFREE()\n", __FILE__, __LINE__, (p)); \ + free((caddr_t)(p), M_SECA); \ } while (0) #endif -#define KEY_NEWBUF(dst, t, src, len) \ - ((dst) = (t)key_newbuf((src), (len))) - -#ifdef RESTRICTED_DIR -#define KEY_SADBLOOP(statements) \ - {\ - u_int diridx, dir;\ - u_int stateidx;\ - for (diridx = 0; diridx < _ARRAYLEN(saorder_dir_any); diridx++) {\ - dir = saorder_dir_any[diridx];\ - for (saidx = (struct secasindex *)saidxtree[dir].head;\ - saidx != NULL;\ - saidx = saidx->next) {\ - for (stateidx = 0;\ - stateidx < _ARRAYLEN(saorder_state_any); \ - stateidx++) {\ - state = saorder_state_any[stateidx];\ - {statements}\ - }\ - }\ - }\ - } - -#define KEY_SPDBLOOP(statements) \ - {\ - u_int diridx, dir;\ - for (diridx = 0; diridx < _ARRAYLEN(saorder_dir_any); diridx++) {\ - dir = saorder_dir_any[diridx];\ - for (sp = (struct secpolicy *)sptree[dir].head;\ - sp != NULL;\ - sp = sp->next) {\ - {statements}\ - }\ - }\ - } -#else -#define KEY_SADBLOOP(statements) \ - {\ - u_int stateidx;\ - for (saidx = (struct secasindex *)saidxtree.head;\ - saidx != NULL;\ - saidx = saidx->next) {\ - for (stateidx = 0;\ - stateidx < _ARRAYLEN(saorder_state_any); \ - stateidx++) {\ - state = saorder_state_any[stateidx];\ - {statements}\ - }\ - }\ - } - -#define KEY_SPDBLOOP(statements) \ - {\ - for (sp = (struct secpolicy *)sptree.head;\ - sp != NULL;\ - sp = sp->next) {\ - {statements}\ - }\ - } -#endif +/* + * set parameters into secpolicyindex buffer. + * Must allocate secpolicyindex buffer passed to this function. + */ +#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, idx) \ +do { \ + bzero((idx), sizeof(struct secpolicyindex)); \ + (idx)->dir = (_dir); \ + (idx)->prefs = (ps); \ + (idx)->prefd = (pd); \ + (idx)->ul_proto = (ulp); \ + bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \ + bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \ +} while (0) +/* + * set parameters into secasindex buffer. + * Must allocate secasindex buffer before calling this function. + */ +#define KEY_SETSECASIDX(p, m, s, d, idx) \ +do { \ + bzero((idx), sizeof(struct secasindex)); \ + (idx)->proto = (p); \ + (idx)->mode = (m)->sadb_msg_mode; \ + (idx)->reqid = (m)->sadb_msg_reqid; \ + bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \ + bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \ +} while (0) /* key statistics */ struct _keystat { u_long getspi_count; /* the avarage of count to try to get new SPI */ } keystat; -#if 0 -static int key_checkpolicy __P((struct secpolicy *)); +static struct secasvar *key_allocsa_policy __P((struct secasindex *saidx)); +static void key_freesp_so __P((struct secpolicy **sp)); +static struct secasvar *key_do_allocsa_policy __P((struct secashead *sah, + u_int state)); +static void key_delsp __P((struct secpolicy *sp)); +static struct secpolicy *key_getsp __P((struct secpolicyindex *spidx)); +static u_int32_t key_newreqid __P((void)); +static struct sadb_msg *key_spdadd __P((caddr_t *mhp)); +static struct sadb_msg *key_spddelete __P((caddr_t *mhp)); +static struct sadb_msg *key_spdflush __P((caddr_t *mhp)); +static int key_spddump __P((caddr_t *mhp, struct socket *so, int target)); +static struct mbuf *key_setdumpsp __P((struct secpolicy *sp, + u_int8_t type, u_int32_t seq, u_int32_t pid)); +static u_int key_getspmsglen __P((struct secpolicy *sp)); +static u_int key_getspreqmsglen __P((struct secpolicy *sp)); +static struct secashead *key_newsah __P((struct secasindex *saidx)); +static void key_delsah __P((struct secashead *sah)); +static struct secasvar *key_newsav __P((caddr_t *mhp, struct secashead *sah)); +static void key_delsav __P((struct secasvar *sav)); +static struct secashead *key_getsah __P((struct secasindex *saidx)); +static struct secasvar *key_checkspidup __P((struct secasindex *saidx, + u_int32_t spi)); +static struct secasvar *key_getsavbyspi __P((struct secashead *sah, + u_int32_t spi)); +static int key_setsaval __P((struct secasvar *sav, caddr_t *mhp)); +static u_int key_getmsglen __P((struct secasvar *sav)); +static int key_mature __P((struct secasvar *sav)); +static u_int key_setdumpsa __P((struct sadb_msg *newmsg, struct secasvar *sav, + u_int8_t type, u_int8_t satype, + u_int32_t seq, u_int32_t pid)); +#if 1 +static int key_setsadbmsg_m __P((struct mbuf *, u_int8_t type, int tlen, + u_int8_t satype, u_int32_t seq, pid_t pid, + u_int8_t mode, u_int32_t reqid, + u_int8_t reserved1, u_int32_t reserved2)); #endif -#ifdef RESTRICTED_DIR -static struct secas *key_allocsa_policy __P((struct secindex *, - struct ipsecrequest *, int, u_int *)); -#else -static struct secas *key_allocsa_policy __P((struct secindex *, - struct ipsecrequest *)); -#endif -static struct secas *key_do_allocsa_policy __P((struct secasindex *, - u_int, u_int, u_int)); - -#ifdef RESTRICTED_DIR -static struct secasindex *key_newsaidx __P((struct secindex *, u_int)); -#else -static struct secasindex *key_newsaidx __P((struct secindex *)); -#endif -static void key_delsaidx __P((struct secasindex *)); -static struct secas *key_newsa __P((caddr_t *, struct secasindex *)); -#if 0 -static struct secas *key_newsa2 __P((u_int, struct secasindex *)); -#endif -static void key_delsa __P((struct secas *)); - -#ifdef RESTRICTED_DIR -static struct secasindex *key_getsaidx __P((struct secindex *, u_int)); -#else -static struct secasindex *key_getsaidx __P((struct secindex *)); -#endif -static struct secasindex *key_getsaidxfromany __P((struct secindex *)); -static struct secas *key_checkspi __P((u_int32_t, u_int)); -static struct secas *key_getsabyspi __P((struct secasindex *, u_int, u_int32_t)); -static int key_setsaval __P((struct secas *, caddr_t *)); -static u_int key_getmsglen __P((struct secas *)); -static int key_mature __P((struct secas *)); -static u_int key_setdumpsa __P((struct secas *, struct sadb_msg *)); -static void key_issaidx_dead __P((struct secasindex *)); -static caddr_t key_copysadbext __P((caddr_t, caddr_t)); -static caddr_t key_setsadbaddr __P((caddr_t, u_int, u_int, - caddr_t, u_int, u_int, u_int)); - -static void key_delsp __P((struct secpolicy *)); -#ifdef RESTRICTED_DIR -static struct secpolicy *key_getinspointforsp __P((struct secpolicy *, u_int)); -static struct secpolicy *key_getsp __P((struct secindex *, u_int)); -#else -static struct secpolicy *key_getinspointforsp __P((struct secpolicy *)); -static struct secpolicy *key_getsp __P((struct secindex *)); -#endif -static struct sadb_msg *key_spdadd __P((caddr_t *)); -static struct sadb_msg *key_spddelete __P((caddr_t *)); -static struct sadb_msg *key_spdflush __P((caddr_t *)); -static int key_spddump __P((caddr_t *, struct socket *, int)); -static u_int key_setdumpsp __P((struct secpolicy *, struct sadb_msg *)); -static u_int key_getspmsglen __P((struct secpolicy *)); -static u_int key_getspreqmsglen __P((struct secpolicy *)); - -static void *key_newbuf __P((void *, u_int)); -static void key_insnode __P((void *, void *, void *)); -static void key_remnode __P((void *)); -#ifdef RESTRICTED_DIR -static u_int key_checkdir __P((struct secindex *, struct sockaddr *)); -static u_int key_getaddrtype __P((u_int, caddr_t, u_int)); +static caddr_t key_setsadbmsg __P((caddr_t buf, u_int8_t type, int tlen, + u_int8_t satype, u_int32_t seq, pid_t pid, + u_int8_t mode, u_int32_t reqid, + u_int8_t reserved1, u_int32_t reserved2)); +static caddr_t key_setsadbsa __P((caddr_t buf, struct secasvar *sav)); +#if 1 +static int key_setsadbaddr_m __P((struct mbuf *m, u_int16_t exttype, + struct sockaddr *saddr, u_int8_t prefixlen, u_int16_t ul_proto)); #endif +static caddr_t key_setsadbaddr __P((caddr_t buf, u_int16_t exttype, + struct sockaddr *saddr, u_int8_t prefixlen, u_int16_t ul_proto)); +static caddr_t key_setsadbident + __P((caddr_t buf, u_int16_t exttype, u_int16_t idtype, + caddr_t string, int stringlen, u_int64_t id)); +static caddr_t key_setsadbext __P((caddr_t p, caddr_t ext)); +static void *key_newbuf __P((void *src, u_int len)); #ifdef INET6 -static int key_ismyaddr6 __P((caddr_t)); +static int key_ismyaddr6 __P((caddr_t addr)); #endif -#ifdef RESTRICTED_DIR -static int key_ismysubnet __P((u_int, caddr_t, u_int)); -static int key_isloopback __P((u_int, caddr_t)); -#endif /*RESTRICTED_DIR*/ -static int key_cmpidx __P((struct secindex *, struct secindex *)); -static int key_cmpidxwithmask __P((struct secindex *, struct secindex *)); -static int key_bbcmp __P((caddr_t, caddr_t, u_int)); +#if 0 +static int key_isloopback __P((u_int family, caddr_t addr)); +#endif +static int key_cmpsaidx_exactly + __P((struct secasindex *saidx0, struct secasindex *saidx1)); +static int key_cmpsaidx_withmode + __P((struct secasindex *saidx0, struct secasindex *saidx1)); +static int key_cmpspidx_exactly + __P((struct secpolicyindex *spidx0, struct secpolicyindex *spidx1)); +static int key_cmpspidx_withmask + __P((struct secpolicyindex *spidx0, struct secpolicyindex *spidx1)); +static int key_bbcmp __P((caddr_t p1, caddr_t p2, u_int bits)); +static u_int16_t key_satype2proto __P((u_int8_t satype)); +static u_int8_t key_proto2satype __P((u_int16_t proto)); -static struct sadb_msg *key_getspi __P((caddr_t *)); -static u_int32_t key_do_getnewspi __P((struct sadb_spirange *, u_int)); -static struct sadb_msg *key_update __P((caddr_t *)); -static struct secas *key_getsabyseq __P((struct secasindex *, u_int32_t)); -static struct sadb_msg *key_add __P((caddr_t *)); -struct sadb_msg *key_getmsgbuf_x1 __P((caddr_t *)); -static struct sadb_msg *key_delete __P((caddr_t *)); -static struct sadb_msg *key_get __P((caddr_t *)); -static int key_acquire __P((struct secindex *, u_int, struct sockaddr *)); -static struct secacq *key_newacq __P((struct secindex *, u_int, struct sockaddr *)); -static void key_delacq __P((struct secacq *)); -static struct secacq *key_getacq __P((struct secindex *, u_int, struct sockaddr *)); -static struct secacq *key_getacqbyseq __P((u_int32_t)); -static struct sadb_msg *key_acquire2 __P((caddr_t *)); -static struct sadb_msg *key_register __P((caddr_t *, struct socket *)); -static int key_expire __P((struct secas *sa)); -static struct sadb_msg *key_flush __P((caddr_t *)); -static int key_dump __P((caddr_t *, struct socket *, int)); -static void key_promisc __P((caddr_t *, struct socket *)); -static int key_sendall __P((struct sadb_msg *, u_int)); - -static int key_check __P((struct sadb_msg *, caddr_t *)); +static struct sadb_msg *key_getspi __P((caddr_t *mhp)); +static u_int32_t key_do_getnewspi __P((struct sadb_spirange *spirange, + struct secasindex *saidx)); +static struct sadb_msg *key_update __P((caddr_t *mhp)); +#ifdef IPSEC_DOSEQCHECK +static struct secasvar *key_getsavbyseq __P((struct secashead *sah, + u_int32_t seq)); +#endif +static struct sadb_msg *key_add __P((caddr_t *mhp)); +static int key_setident __P((struct secashead *sah, caddr_t *mhp)); +static struct sadb_msg *key_getmsgbuf_x1 __P((caddr_t *mhp)); +static struct sadb_msg *key_delete __P((caddr_t *mhp)); +static struct sadb_msg *key_get __P((caddr_t *mhp)); +static int key_acquire __P((struct secasindex *saidx, + struct secpolicyindex *spidx)); +static struct secacq *key_newacq __P((struct secasindex *saidx)); +static struct secacq *key_getacq __P((struct secasindex *saidx)); +static struct secacq *key_getacqbyseq __P((u_int32_t seq)); +static struct sadb_msg *key_acquire2 __P((caddr_t *mhp)); +static struct sadb_msg *key_register __P((caddr_t *mhp, struct socket *so)); +static int key_expire __P((struct secasvar *sav)); +static struct sadb_msg *key_flush __P((caddr_t *mhp)); +static int key_dump __P((caddr_t *mhp, struct socket *so, int target)); +static void key_promisc __P((caddr_t *mhp, struct socket *so)); +static int key_sendall __P((struct sadb_msg *msg, u_int len)); +static int key_align __P((struct sadb_msg *msg, caddr_t *mhp)); #if 0 static const char *key_getfqdn __P((void)); static const char *key_getuserfqdn __P((void)); #endif - -static void key_sa_chgstate __P((struct secas *, u_int)); +static void key_sa_chgstate __P((struct secasvar *sav, u_int8_t state)); +static caddr_t key_appendmbuf __P((struct mbuf *, int)); /* %%% IPsec policy management */ /* @@ -389,75 +349,53 @@ static void key_sa_chgstate __P((struct secas *, u_int)); * others: found and return the pointer. */ struct secpolicy * -key_allocsp(idx) - struct secindex *idx; +key_allocsp(spidx, dir) + struct secpolicyindex *spidx; + u_int dir; { struct secpolicy *sp; -#ifdef RESTRICTED_DIR - u_int *order; - u_int diridx, diridxlen, dir; -#endif + int s; /* sanity check */ - if (idx == NULL) + if (spidx == NULL) panic("key_allocsp: NULL pointer is passed.\n"); -#ifdef RESTRICTED_DIR - /* checking the direciton. */ - dir = key_checkdir(idx, NULL); + /* check direction */ switch (dir) { - case SADB_X_DIR_INBOUND: - order = saorder_dir_input; - diridxlen = _ARRAYLEN(saorder_dir_input); - break; - case SADB_X_DIR_OUTBOUND: - order = saorder_dir_output; - diridxlen = _ARRAYLEN(saorder_dir_output); - break; - case SADB_X_DIR_BIDIRECT: - case SADB_X_DIR_INVALID: - order = saorder_dir_any; - diridxlen = _ARRAYLEN(saorder_dir_any); + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: break; default: panic("key_allocsp: Invalid direction is passed.\n"); } -#endif /* get a SP entry */ -#ifdef RESTRICTED_DIR - for (diridx = 0; diridx < diridxlen; diridx++) { + s = splsoftnet(); /*called from softclock()*/ + KEYDEBUG(KEYDEBUG_IPSEC_DATA, + printf("*** objects\n"); + kdebug_secpolicyindex(spidx)); - dir = order[diridx]; - for (sp = (struct secpolicy *)sptree[dir].head; - sp != NULL; - sp = sp->next) { - - if (sp->state == IPSEC_SPSTATE_DEAD) - continue; - - if (key_cmpidxwithmask(&sp->idx, idx)) - goto found; - } - } -#else - for (sp = (struct secpolicy *)sptree.head; - sp != NULL; - sp = sp->next) { + LIST_FOREACH(sp, &sptree[dir], chain) { + KEYDEBUG(KEYDEBUG_IPSEC_DATA, + printf("*** in SPD\n"); + kdebug_secpolicyindex(&sp->spidx)); if (sp->state == IPSEC_SPSTATE_DEAD) continue; - - if (key_cmpidxwithmask(&sp->idx, idx)) + if (key_cmpspidx_withmask(&sp->spidx, spidx)) goto found; } -#endif + splx(s); return NULL; found: + /* sanity check */ + KEY_CHKSPDIR(sp->spidx.dir, dir, "key_allocsp"); + /* found a SPD entry */ sp->refcnt++; + splx(s); KEYDEBUG(KEYDEBUG_IPSEC_STAMP, printf("DP key_allocsp cause refcnt++:%d SP:%p\n", sp->refcnt, sp)); @@ -465,71 +403,30 @@ found: return sp; } -#if 0 /* - * checking each SA entries in SP to acquire. - * OUT: 0: valid. - * ENOENT: policy is valid, but some SA is on acquiring. - */ -int -key_checkpolicy(sp) - struct secpolicy *sp; -{ - struct ipsecrequest *isr; - - /* sanity check */ - if (sp == NULL) - panic("key_checkpolicy: NULL pointer is passed.\n"); - - /* checking policy */ - switch (sp->policy) { - case IPSEC_POLICY_DISCARD: - case IPSEC_POLICY_NONE: - /* no need to check SA entries */ - return 0; - /* NOTREACHED */ - case IPSEC_POLICY_IPSEC: - if (sp->req == NULL) - panic("key_checkpolicy: No IPsec request specified.\n"); - break; - default: - panic("key_checkpolicy: Invalid policy defined.\n"); - } - - /* checking each IPsec request. */ - for (isr = sp->req; isr != NULL; isr = isr->next) { - if (key_checkrequest(isr)) - return ENOENT; - } - - return 0; -} -#endif - -/* - * checking each request entries in SP to acquire. + * allocating a SA entry for a *OUTBOUND* packet. + * checking each request entries in SP, and acquire SA if need. * OUT: 0: there are valid requests. * ENOENT: policy may be valid, but SA with REQUIRE is on acquiring. */ int -key_checkrequest(isr) +key_checkrequest(isr, saidx) struct ipsecrequest *isr; + struct secasindex *saidx; { u_int level; int error; /* sanity check */ - if (isr == NULL) + if (isr == NULL || saidx == NULL) panic("key_checkrequest: NULL pointer is passed.\n"); - /* checking mode */ - switch (isr->mode) { + /* check mode */ + switch (saidx->mode) { case IPSEC_MODE_TRANSPORT: - break; case IPSEC_MODE_TUNNEL: - if (isr->proxy == NULL) - panic("key_checkrequest: No proxy specified.\n"); break; + case IPSEC_MODE_ANY: default: panic("key_checkrequest: Invalid policy defined.\n"); } @@ -537,110 +434,64 @@ key_checkrequest(isr) /* get current level */ level = ipsec_get_reqlevel(isr); - /* new SA allocation for current policy */ - if (isr->sa != NULL) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP checkrequest calls free SA:%p\n", isr->sa)); - key_freesa(isr->sa); - isr->sa = NULL; + /* + * We do allocate new SA only if the state of SA in the holder is + * SADB_SASTATE_DEAD. The SA for outbound must be the oldest. + */ + if (isr->sav != NULL) { + if (isr->sav->sah == NULL) + panic("key_checkrequest: sah is null.\n"); + if (isr->sav == (struct secasvar *)LIST_FIRST( + &isr->sav->sah->savtree[SADB_SASTATE_DEAD])) { + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP checkrequest calls free SA:%p\n", + isr->sav)); + key_freesav(isr->sav); + isr->sav = NULL; + } } -#ifdef RESTRICTED_DIR - isr->sa = key_allocsa_policy(&isr->sp->idx, isr, - _ARRAYLEN(saorder_dir_output), - saorder_dir_output); -#else - isr->sa = key_allocsa_policy(&isr->sp->idx, isr); -#endif + /* new SA allocation if no SA found. */ + if (isr->sav == NULL) + isr->sav = key_allocsa_policy(saidx); /* When there is SA. */ - if (isr->sa != NULL) + if (isr->sav != NULL) return 0; /* there is no SA */ - { - u_int proto; - - /* mapping IPPROTO to SADB_SATYPE */ - switch (isr->proto) { - case IPPROTO_ESP: - proto = SADB_SATYPE_ESP; - break; - case IPPROTO_AH: - proto = SADB_SATYPE_AH; - break; -#if 1 /*nonstandard*/ - case IPPROTO_IPCOMP: - proto = SADB_X_SATYPE_IPCOMP; - break; -#endif - default: - panic("key_checkrequest: Invalid proto type passed.\n"); - } - - if ((error = key_acquire(&isr->sp->idx, proto, isr->proxy)) != 0) { + if ((error = key_acquire(saidx, &isr->sp->spidx)) != 0) { /* XXX What I do ? */ +#ifdef IPSEC_DEBUG printf("key_checkrequest: error %d returned " "from key_acquire.\n", error); +#endif return error; } - } return level == IPSEC_LEVEL_REQUIRE ? ENOENT : 0; } /* - * allocating a SA for policy entry from SADB for the direction specified. - * NOTE: searching SADB of aliving state. + * allocating a SA for policy entry from SAD. + * NOTE: searching SAD of aliving state. * OUT: NULL: not found. * others: found and return the pointer. */ -static struct secas * -#ifdef RESTRICTED_DIR -key_allocsa_policy(idx, isr, diridxplen, diridxp) - struct secindex *idx; - struct ipsecrequest *isr; - int diridxplen; - u_int diridxp[]; -#else -key_allocsa_policy(idx, isr) - struct secindex *idx; - struct ipsecrequest *isr; -#endif -{ +static struct secasvar * +key_allocsa_policy(saidx) struct secasindex *saidx; - struct secas *sa; +{ + struct secashead *sah; + struct secasvar *sav; u_int stateidx, state; -#ifdef RESTRICTED_DIR - u_int diridx, dir; -#endif -#ifdef RESTRICTED_DIR - for (diridx = 0; diridx < diridxplen; diridx++) { - - dir = diridxp[diridx]; - - /* there is no SP in this tree */ - if (saidxtree[dir].head == NULL) + LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) continue; - - for (saidx = (struct secasindex *)saidxtree[dir].head; - saidx != NULL; - saidx = saidx->next) { - - if (key_cmpidxwithmask(&saidx->idx, idx)) - goto found; - } - } -#else - for (saidx = (struct secasindex *)saidxtree.head; - saidx != NULL; - saidx = saidx->next) { - - if (key_cmpidxwithmask(&saidx->idx, idx)) + if (key_cmpsaidx_withmode(&sah->saidx, saidx)) goto found; } -#endif return NULL; @@ -653,171 +504,105 @@ key_allocsa_policy(idx, isr) state = saorder_state_valid[stateidx]; - sa = key_do_allocsa_policy(saidx, isr->proto, isr->mode, state); - if (sa != NULL) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP allocsa_policy cause " - "refcnt++:%d SA:%p\n", - sa->refcnt, sa)); - return sa; - } + sav = key_do_allocsa_policy(sah, state); + if (sav != NULL) + return sav; } return NULL; } /* - * searching SADB with direction, protocol, mode and state. + * searching SAD with direction, protocol, mode and state. * called by key_allocsa_policy(). * OUT: * NULL : not found * others : found, pointer to a SA. */ -static struct secas * -key_do_allocsa_policy(saidx, proto, mode, state) - struct secasindex *saidx; - u_int proto, mode, state; +static struct secasvar * +key_do_allocsa_policy(sah, state) + struct secashead *sah; + u_int state; { - struct secas *sa, *candidate; - - switch (proto) { - case IPPROTO_ESP: - proto = SADB_SATYPE_ESP; - break; - case IPPROTO_AH: - proto = SADB_SATYPE_AH; - break; -#if 1 /*nonstandard*/ - case IPPROTO_IPCOMP: - proto = SADB_X_SATYPE_IPCOMP; - break; -#endif - default: - printf("key_do_allocsa_policy: invalid proto type\n"); - return NULL; - } + struct secasvar *sav, *candidate; /* initilize */ candidate = NULL; - for (sa = (struct secas *)saidx->satree[state].head; - sa != NULL; - sa = sa->next) { + LIST_FOREACH(sav, &sah->savtree[state], chain) { /* sanity check */ - if (sa->state != state) { - printf("key_do_allocsa_policy: state mismatch " - "(DB:%u param:%u), anyway continue.\n", - sa->state, state); - continue; - } - - if (sa->type != proto) - continue; - - /* check transport mode */ - if (mode == IPSEC_MODE_TRANSPORT && sa->proxy != NULL) - continue; - - /* check proxy address for tunnel mode */ - if (mode == IPSEC_MODE_TUNNEL && sa->proxy == NULL) - continue; + KEY_CHKSASTATE(sav->state, state, "key_do_allocsa_policy"); /* initialize */ if (candidate == NULL) { - candidate = sa; + candidate = sav; continue; } /* Which SA is the better ? */ /* sanity check 2 */ - if (candidate->lft_c == NULL || sa->lft_c == NULL) { - /*XXX do panic ? */ - printf("key_do_allocsa_policy: " + if (candidate->lft_c == NULL || sav->lft_c == NULL) + panic("key_do_allocsa_policy: " "lifetime_current is NULL.\n"); - continue; - } /* XXX What the best method is to compare ? */ - if (candidate->lft_c->sadb_lifetime_addtime < - sa->lft_c->sadb_lifetime_addtime) { - candidate = sa; + if (candidate->lft_c->sadb_lifetime_addtime > + sav->lft_c->sadb_lifetime_addtime) { + candidate = sav; continue; } } - if (candidate) + if (candidate) { candidate->refcnt++; + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP allocsa_policy cause " + "refcnt++:%d SA:%p\n", + candidate->refcnt, candidate)); + } return candidate; } /* * allocating a SA entry for a *INBOUND* packet. - * Must call key_freesa() later. - * OUT: positive: pointer to a sa. + * Must call key_freesav() later. + * OUT: positive: pointer to a sav. * NULL: not found, or error occured. + * + * In the comparison, source address will be ignored for RFC2401 conformance. + * To quote, from section 4.1: + * A security association is uniquely identified by a triple consisting + * of a Security Parameter Index (SPI), an IP Destination Address, and a + * security protocol (AH or ESP) identifier. + * Note that, however, we do need to keep source address in IPsec SA. + * IPsec SA. IKE specification and PF_KEY specification do assume that we + * keep source address in IPsec SA. We see a tricky situation here. */ -struct secas * +struct secasvar * key_allocsa(family, src, dst, proto, spi) u_int family, proto; caddr_t src, dst; u_int32_t spi; { - struct secasindex *saidx; - struct secas *sa; + struct secashead *sah; + struct secasvar *sav; u_int stateidx, state; -#ifdef RESTRICTED_DIR - u_int dir; -#endif + int s; /* sanity check */ if (src == NULL || dst == NULL) panic("key_allocsa: NULL pointer is passed.\n"); - /* fix proto to use. */ - switch (proto) { - case IPPROTO_ESP: - proto = SADB_SATYPE_ESP; - break; - case IPPROTO_AH: - proto = SADB_SATYPE_AH; - break; -#if 1 /*nonstandard*/ - case IPPROTO_IPCOMP: - proto = SADB_X_SATYPE_IPCOMP; - break; -#endif - default: - printf("key_allocsa: invalid protocol type passed.\n"); - return NULL; - } - -#ifdef RESTRICTED_DIR - /* set direction */ - if (key_isloopback(family, dst)) - dir = SADB_X_DIR_BIDIRECT; - else - dir = SADB_X_DIR_INBOUND; -#endif - /* - * searching SADB. - * transport mode case looks trivial. - * for tunnel mode case (sa->proxy != 0), we will only be able to - * check (spi, dst). - * when ESP tunnel packet is received, internal IP header is + * searching SAD. + * XXX: to be checked internal IP header somewhere. Also when + * IPsec tunnel packet is received. But ESP tunnel mode is * encrypted so we can't check internal IP header. - * - * IP1 ESP(IP2 payload) - * sa->proxy == IP1.dst (my addr) - * sa->saidx->idx.src == IP2.src - * sa->saidx->idx.dst == IP2.dst */ -#ifdef RESTRICTED_DIR - for (saidx = (struct secasindex *)saidxtree[dir].head; - saidx != NULL; - saidx = saidx->next) { + s = splsoftnet(); /*called from softclock()*/ + LIST_FOREACH(sah, &sahtree, chain) { /* search valid state */ for (stateidx = 0; @@ -825,96 +610,42 @@ key_allocsa(family, src, dst, proto, spi) stateidx++) { state = saorder_state_valid[stateidx]; - for (sa = (struct secas *)saidx->satree[state].head; - sa != NULL; - sa = sa->next) { + LIST_FOREACH(sav, &sah->savtree[state], chain) { /* sanity check */ - if (sa->state != state) { - printf("key_allocsa: " - "invalid sa->state " - "(queue: %d SA: %d)\n", - state, sa->state); + KEY_CHKSASTATE(sav->state, state, "key_allocsav"); + if (proto != sav->sah->saidx.proto) continue; - } - - if (sa->type != proto) - continue; - if (sa->spi != spi) + if (spi != sav->spi) continue; - if (sa->proxy == NULL - && key_bbcmp(src, (caddr_t)&sa->saidx->idx.src, - sa->saidx->idx.prefs) - && key_bbcmp(dst, (caddr_t)&sa->saidx->idx.dst, - sa->saidx->idx.prefd)) { - goto found; - } - - if (sa->proxy != NULL - && bcmp(dst, _INADDRBYSA(sa->proxy), - _INALENBYAF(sa->proxy->sa_family)) == 0) { - goto found; - } - } - } - } -#else - for (saidx = (struct secasindex *)saidxtree.head; - saidx != NULL; - saidx = saidx->next) { - - /* search valid state */ - for (stateidx = 0; - stateidx < _ARRAYLEN(saorder_state_valid); - stateidx++) { - - state = saorder_state_valid[stateidx]; - for (sa = (struct secas *)saidx->satree[state].head; - sa != NULL; - sa = sa->next) { - - /* sanity check */ - if (sa->state != state) { - printf("key_allocsa: " - "invalid sa->state " - "(queue: %d SA: %d)\n", - state, sa->state); +#if 0 /* don't check src */ + if (!key_bbcmp(src, + _INADDRBYSA(&sav->sah->saidx.src), + _INALENBYAF(sav->sah->saidx.src.ss_family) << 3)) continue; - } - - if (sa->type != proto) - continue; - if (sa->spi != spi) - continue; - - if (sa->proxy == NULL - && key_bbcmp(src, (caddr_t)&sa->saidx->idx.src, - sa->saidx->idx.prefs) - && key_bbcmp(dst, (caddr_t)&sa->saidx->idx.dst, - sa->saidx->idx.prefd)) { - goto found; - } - - if (sa->proxy != NULL - && bcmp(dst, _INADDRBYSA(sa->proxy), - _INALENBYAF(sa->proxy->sa_family)) == 0) { - goto found; - } - } - } - } #endif + if (!key_bbcmp(dst, + _INADDRBYSA(&sav->sah->saidx.dst), + _INALENBYAF(sav->sah->saidx.dst.ss_family) << 3)) + continue; + + goto found; + } + } + } /* not found */ + splx(s); return NULL; found: - sa->refcnt++; + sav->refcnt++; + splx(s); KEYDEBUG(KEYDEBUG_IPSEC_STAMP, printf("DP allocsa cause refcnt++:%d SA:%p\n", - sa->refcnt, sa)); - return sa; + sav->refcnt, sav)); + return sav; } /* @@ -948,8 +679,6 @@ void key_freeso(so) struct socket *so; { - struct secpolicy **sp; - /* sanity check */ if (so == NULL) panic("key_freeso: NULL pointer is passed.\n"); @@ -961,33 +690,44 @@ key_freeso(so) struct inpcb *pcb = sotoinpcb(so); /* Does it have a PCB ? */ - if (pcb == 0) + if (pcb == NULL) return; - sp = &pcb->inp_sp; + key_freesp_so(&pcb->inp_sp->sp_in); + key_freesp_so(&pcb->inp_sp->sp_out); } break; #endif #ifdef INET6 case PF_INET6: { - struct in6pcb *pcb = sotoin6pcb(so); + struct in6pcb *pcb = sotoin6pcb(so); /* Does it have a PCB ? */ - if (pcb == 0) + if (pcb == NULL) return; - sp = &pcb->in6p_sp; + key_freesp_so(&pcb->in6p_sp->sp_in); + key_freesp_so(&pcb->in6p_sp->sp_out); } break; #endif /* INET6 */ default: +#ifdef IPSEC_DEBUG printf("key_freeso: unknown address family=%d.\n", so->so_proto->pr_domain->dom_family); +#endif return; } + return; +} + +static void +key_freesp_so(sp) + struct secpolicy **sp; +{ /* sanity check */ - if (*sp == NULL) - panic("key_freeso: sp == NULL\n"); + if (sp == NULL || *sp == NULL) + panic("key_freesp_so: sp == NULL\n"); switch ((*sp)->policy) { case IPSEC_POLICY_IPSEC: @@ -1000,7 +740,7 @@ key_freeso(so) case IPSEC_POLICY_BYPASS: return; default: - panic("key_freeso: Invalid policy found %d", (*sp)->policy); + panic("key_freesp_so: Invalid policy found %d", (*sp)->policy); } return; @@ -1012,20 +752,20 @@ key_freeso(so) * for a policy. */ void -key_freesa(sa) - struct secas *sa; +key_freesav(sav) + struct secasvar *sav; { /* sanity check */ - if (sa == NULL) - panic("key_freesa: NULL pointer is passed.\n"); + if (sav == NULL) + panic("key_freesav: NULL pointer is passed.\n"); - sa->refcnt--; + sav->refcnt--; KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP freesa cause refcnt--:%d SA:%p SPI %d\n", - sa->refcnt, sa, (u_int32_t)ntohl(sa->spi))); + printf("DP freesav cause refcnt--:%d SA:%p SPI %d\n", + sav->refcnt, sav, (u_int32_t)ntohl(sav->spi))); - if (sa->refcnt == 0) - key_delsa(sa); + if (sav->refcnt == 0) + key_delsav(sav); return; } @@ -1038,6 +778,8 @@ static void key_delsp(sp) struct secpolicy *sp; { + int s; + /* sanity check */ if (sp == NULL) panic("key_delsp: NULL pointer is passed.\n"); @@ -1047,33 +789,32 @@ key_delsp(sp) if (sp->refcnt > 0) return; /* can't free */ + s = splsoftnet(); /*called from softclock()*/ /* remove from SP index */ - if (sp->spt != NULL) - key_remnode(sp); - - key_delsecidx(&sp->idx); + if (__LIST_CHAINED(sp)) + LIST_REMOVE(sp, chain); { - struct ipsecrequest *isr = sp->req, *isr_next; + struct ipsecrequest *isr = sp->req, *nextisr; while (isr != NULL) { - if (isr->proxy != NULL) - KFREE(isr->proxy); - if (isr->sa != NULL) { + if (isr->sav != NULL) { KEYDEBUG(KEYDEBUG_IPSEC_STAMP, printf("DP delsp calls free SA:%p\n", - isr->sa)); - key_freesa(isr->sa); - isr->sa = NULL; + isr->sav)); + key_freesav(isr->sav); + isr->sav = NULL; } - isr_next = isr->next; + nextisr = isr->next; KFREE(isr); - isr = isr_next; + isr = nextisr; } } - KFREE(sp); + keydb_delsecpolicy(sp); + + splx(s); return; } @@ -1084,80 +825,23 @@ key_delsp(sp) * others : found, pointer to a SP. */ static struct secpolicy * -#ifdef RESTRICTED_DIR -key_getinspointforsp(sp, dir) - struct secpolicy *sp; - u_int dir; -#else -key_getinspointforsp(sp) - struct secpolicy *sp; -#endif -{ - if (sp == NULL) - return NULL; - - /* XXX Do code !*/ - return NULL; - -#ifdef RESTRICTED_DIR - for (sp = (struct secpolicy *)sptree[dir].head; - sp != NULL; - sp = sp->next) { - /* XXX Do code ! */ - ; - } -#else - for (sp = (struct secpolicy *)sptree.head; - sp != NULL; - sp = sp->next) { - /* XXX Do code ! */ - ; - } -#endif - - return NULL; -} - -/* - * search SPD - * OUT: NULL : not found - * others : found, pointer to a SP. - */ -static struct secpolicy * -#ifdef RESTRICTED_DIR -key_getsp(idx, dir) - struct secindex *idx; - u_int dir; -#else -key_getsp(idx) - struct secindex *idx; -#endif +key_getsp(spidx) + struct secpolicyindex *spidx; { struct secpolicy *sp; /* sanity check */ - if (idx == NULL) + if (spidx == NULL) panic("key_getsp: NULL pointer is passed.\n"); -#ifdef RESTRICTED_DIR - for (sp = (struct secpolicy *)sptree[dir].head; - sp != NULL; - sp = sp->next) { - if (sp->state != IPSEC_SPSTATE_ALIVE) + LIST_FOREACH(sp, &sptree[spidx->dir], chain) { + if (sp->state == IPSEC_SPSTATE_DEAD) continue; - if (key_cmpidx(&sp->idx, idx)) + if (key_cmpspidx_exactly(spidx, &sp->spidx)) { + sp->refcnt++; return sp; + } } -#else - for (sp = (struct secpolicy *)sptree.head; - sp != NULL; - sp = sp->next) { - if (sp->state != IPSEC_SPSTATE_ALIVE) - continue; - if (key_cmpidx(&sp->idx, idx)) - return sp; - } -#endif return NULL; } @@ -1167,12 +851,9 @@ key_newsp() { struct secpolicy *newsp = NULL; - KMALLOC(newsp, struct secpolicy *, sizeof(*newsp)); - if (newsp == NULL) { - printf("key_newsp: No more memory.\n"); - return NULL; - } - bzero(newsp, sizeof(*newsp)); + newsp = keydb_newsecpolicy(); + if (!newsp) + return newsp; newsp->refcnt = 1; newsp->req = NULL; @@ -1182,21 +863,37 @@ key_newsp() /* * create secpolicy structure from sadb_x_policy structure. - * NOTE: `state', `secindex' in secpolicy structure are not set, + * NOTE: `state', `secpolicyindex' in secpolicy structure are not set, * so must be set properly later. */ struct secpolicy * -key_msg2sp(xpl0) +key_msg2sp(xpl0, len, error) struct sadb_x_policy *xpl0; + size_t len; + int *error; { struct secpolicy *newsp; /* sanity check */ if (xpl0 == NULL) panic("key_msg2sp: NULL pointer was passed.\n"); - - if ((newsp = key_newsp()) == NULL) + if (len < sizeof(*xpl0)) + panic("key_msg2sp: invalid length.\n"); + if (len != PFKEY_EXTLEN(xpl0)) { +#ifdef IPSEC_DEBUG + printf("key_msg2sp: Invalid msg length.\n"); +#endif + *error = EINVAL; return NULL; + } + + if ((newsp = key_newsp()) == NULL) { + *error = ENOBUFS; + return NULL; + } + + newsp->spidx.dir = xpl0->sadb_x_policy_dir; + newsp->policy = xpl0->sadb_x_policy_type; /* check policy */ switch (xpl0->sadb_x_policy_type) { @@ -1204,7 +901,6 @@ key_msg2sp(xpl0) case IPSEC_POLICY_NONE: case IPSEC_POLICY_ENTRUST: case IPSEC_POLICY_BYPASS: - newsp->policy = xpl0->sadb_x_policy_type; newsp->req = NULL; break; @@ -1213,153 +909,293 @@ key_msg2sp(xpl0) int tlen; struct sadb_x_ipsecrequest *xisr; struct ipsecrequest **p_isr = &newsp->req; - int xxx_len; /* for sanity check */ /* validity check */ - if (PFKEY_UNUNIT64(xpl0->sadb_x_policy_len) <= sizeof(*xpl0)) { + if (PFKEY_EXTLEN(xpl0) <= sizeof(*xpl0)) { +#ifdef IPSEC_DEBUG printf("key_msg2sp: Invalid msg length.\n"); +#endif key_freesp(newsp); + *error = EINVAL; return NULL; } - tlen = PFKEY_UNUNIT64(xpl0->sadb_x_policy_len) - sizeof(*xpl0); - xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl0 - + sizeof(*xpl0)); + tlen = PFKEY_EXTLEN(xpl0) - sizeof(*xpl0); + xisr = (struct sadb_x_ipsecrequest *)(xpl0 + 1); while (tlen > 0) { + /* length check */ + if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) { +#ifdef IPSEC_DEBUG + printf("key_msg2sp: " + "invalid ipsecrequest length.\n"); +#endif + key_freesp(newsp); + *error = EINVAL; + return NULL; + } + + /* allocate request buffer */ KMALLOC(*p_isr, struct ipsecrequest *, sizeof(**p_isr)); if ((*p_isr) == NULL) { +#ifdef IPSEC_DEBUG printf("key_msg2sp: No more memory.\n"); +#endif key_freesp(newsp); + *error = ENOBUFS; return NULL; } + bzero(*p_isr, sizeof(**p_isr)); + /* set values */ (*p_isr)->next = NULL; - (*p_isr)->proto = xisr->sadb_x_ipsecrequest_proto; - (*p_isr)->mode = xisr->sadb_x_ipsecrequest_mode; - (*p_isr)->level = xisr->sadb_x_ipsecrequest_level; - (*p_isr)->proxy = NULL; - (*p_isr)->sa = NULL; - (*p_isr)->sp = newsp; - xxx_len = sizeof(*xisr); + switch (xisr->sadb_x_ipsecrequest_proto) { + case IPPROTO_ESP: + case IPPROTO_AH: +#if 1 /*nonstandard*/ + case IPPROTO_IPCOMP: +#endif + break; + default: +#ifdef IPSEC_DEBUG + printf("key_msg2sp: invalid proto type=%u\n", + xisr->sadb_x_ipsecrequest_proto); +#endif + key_freesp(newsp); + *error = EPROTONOSUPPORT; + return NULL; + } + (*p_isr)->saidx.proto = xisr->sadb_x_ipsecrequest_proto; - /* if tunnel mode ? */ - if (xisr->sadb_x_ipsecrequest_mode ==IPSEC_MODE_TUNNEL){ - struct sockaddr *addr - = (struct sockaddr *)((caddr_t)xisr - + sizeof(*xisr)); + switch (xisr->sadb_x_ipsecrequest_mode) { + case IPSEC_MODE_TRANSPORT: + case IPSEC_MODE_TUNNEL: + break; + case IPSEC_MODE_ANY: + default: +#ifdef IPSEC_DEBUG + printf("key_msg2sp: invalid mode=%u\n", + xisr->sadb_x_ipsecrequest_mode); +#endif + key_freesp(newsp); + *error = EINVAL; + return NULL; + } + (*p_isr)->saidx.mode = xisr->sadb_x_ipsecrequest_mode; - KEY_NEWBUF((*p_isr)->proxy, - struct sockaddr *, - addr, - addr->sa_len); - if ((*p_isr)->proxy == NULL) { - key_freesp(newsp); - return NULL; + switch (xisr->sadb_x_ipsecrequest_level) { + case IPSEC_LEVEL_DEFAULT: + case IPSEC_LEVEL_USE: + case IPSEC_LEVEL_REQUIRE: + break; + case IPSEC_LEVEL_UNIQUE: + /* validity check */ + /* + * If range violation of reqid, kernel will + * update it, don't refuse it. + */ + if (xisr->sadb_x_ipsecrequest_reqid + > IPSEC_MANUAL_REQID_MAX) { +#ifdef IPSEC_DEBUG + printf("key_msg2sp: reqid=%d " + "range violation, " + "updated by kernel.\n", + xisr->sadb_x_ipsecrequest_reqid); +#endif + xisr->sadb_x_ipsecrequest_reqid = 0; } - xxx_len += PFKEY_ALIGN8(addr->sa_len); - } + /* allocate new reqid id if reqid is zero. */ + if (xisr->sadb_x_ipsecrequest_reqid == 0) { + u_int32_t reqid; + if ((reqid = key_newreqid()) == 0) { + key_freesp(newsp); + *error = ENOBUFS; + return NULL; + } + (*p_isr)->saidx.reqid = reqid; + xisr->sadb_x_ipsecrequest_reqid = reqid; + } else { + /* set it for manual keying. */ + (*p_isr)->saidx.reqid = + xisr->sadb_x_ipsecrequest_reqid; + } + break; - /* sanity check */ - if (xisr->sadb_x_ipsecrequest_len != xxx_len) { - printf("key_msg2sp: Invalid request length, " - "reqlen:%d real:%d\n", - xisr->sadb_x_ipsecrequest_len, - xxx_len); + default: +#ifdef IPSEC_DEBUG + printf("key_msg2sp: invalid level=%u\n", + xisr->sadb_x_ipsecrequest_level); +#endif key_freesp(newsp); + *error = EINVAL; return NULL; } + (*p_isr)->level = xisr->sadb_x_ipsecrequest_level; + + /* set IP addresses if there */ + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + struct sockaddr *paddr; + + paddr = (struct sockaddr *)(xisr + 1); + + /* validity check */ + if (paddr->sa_len + > sizeof((*p_isr)->saidx.src)) { +#ifdef IPSEC_DEBUG + printf("key_msg2sp: invalid request " + "address length.\n"); +#endif + key_freesp(newsp); + *error = EINVAL; + return NULL; + } + bcopy(paddr, &(*p_isr)->saidx.src, + paddr->sa_len); + + paddr = (struct sockaddr *)((caddr_t)paddr + + paddr->sa_len); + + /* validity check */ + if (paddr->sa_len + > sizeof((*p_isr)->saidx.dst)) { +#ifdef IPSEC_DEBUG + printf("key_msg2sp: invalid request " + "address length.\n"); +#endif + key_freesp(newsp); + *error = EINVAL; + return NULL; + } + bcopy(paddr, &(*p_isr)->saidx.dst, + paddr->sa_len); + } + + (*p_isr)->sav = NULL; + (*p_isr)->sp = newsp; /* initialization for the next. */ p_isr = &(*p_isr)->next; tlen -= xisr->sadb_x_ipsecrequest_len; - /* sanity check */ - if (tlen < 0) - panic("key_msg2sp: " - "becoming tlen < 0.\n"); + /* validity check */ + if (tlen < 0) { +#ifdef IPSEC_DEBUG + printf("key_msg2sp: becoming tlen < 0.\n"); +#endif + key_freesp(newsp); + *error = EINVAL; + return NULL; + } xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + xisr->sadb_x_ipsecrequest_len); } - - newsp->policy = IPSEC_POLICY_IPSEC; } break; default: +#ifdef IPSEC_DEBUG printf("key_msg2sp: invalid policy type.\n"); +#endif key_freesp(newsp); + *error = EINVAL; return NULL; } + *error = 0; return newsp; } +static u_int32_t +key_newreqid() +{ + static u_int32_t auto_reqid = IPSEC_MANUAL_REQID_MAX + 1; + + auto_reqid = (auto_reqid == ~0 + ? IPSEC_MANUAL_REQID_MAX + 1 : auto_reqid + 1); + + /* XXX should be unique check */ + + return auto_reqid; +} + /* * copy secpolicy struct to sadb_x_policy structure indicated. */ -struct sadb_x_policy * +struct mbuf * key_sp2msg(sp) struct secpolicy *sp; { struct sadb_x_policy *xpl; - int len; + int tlen; caddr_t p; + struct mbuf *m; /* sanity check. */ if (sp == NULL) panic("key_sp2msg: NULL pointer was passed.\n"); - len = key_getspreqmsglen(sp); + tlen = key_getspreqmsglen(sp); - KMALLOC(xpl, struct sadb_x_policy *, len); - if (xpl == NULL) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m && MLEN < tlen) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_free(m); + m = NULL; + } + } + m->m_len = 0; + if (!m || M_TRAILINGSPACE(m) < tlen) { +#ifdef IPSEC_DEBUG printf("key_sp2msg: No more memory.\n"); +#endif + if (m) + m_free(m); return NULL; } - bzero(xpl, len); - xpl->sadb_x_policy_len = PFKEY_UNIT64(len); + m->m_len = tlen; + m->m_next = NULL; + xpl = mtod(m, struct sadb_x_policy *); + bzero(xpl, tlen); + + xpl->sadb_x_policy_len = PFKEY_UNIT64(tlen); xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY; xpl->sadb_x_policy_type = sp->policy; + xpl->sadb_x_policy_dir = sp->spidx.dir; p = (caddr_t)xpl + sizeof(*xpl); /* if is the policy for ipsec ? */ if (sp->policy == IPSEC_POLICY_IPSEC) { struct sadb_x_ipsecrequest *xisr; struct ipsecrequest *isr; - int len; for (isr = sp->req; isr != NULL; isr = isr->next) { xisr = (struct sadb_x_ipsecrequest *)p; - xisr->sadb_x_ipsecrequest_proto = isr->proto; - xisr->sadb_x_ipsecrequest_mode = isr->mode; - xisr->sadb_x_ipsecrequest_level = isr->level; - len = sizeof(*xisr); - /* if tunnel mode ? */ - if (isr->mode == IPSEC_MODE_TUNNEL) { - /* sanity check */ - if (isr->proxy == NULL) { - printf("key_sp2msg: " - "proxy is NULL.\n"); - } else { - bcopy(isr->proxy, - p + sizeof(*xisr), - isr->proxy->sa_len); - len += isr->proxy->sa_len; - } - } - xisr->sadb_x_ipsecrequest_len = PFKEY_ALIGN8(len); - p += xisr->sadb_x_ipsecrequest_len; + xisr->sadb_x_ipsecrequest_proto = isr->saidx.proto; + xisr->sadb_x_ipsecrequest_mode = isr->saidx.mode; + xisr->sadb_x_ipsecrequest_level = isr->level; + xisr->sadb_x_ipsecrequest_reqid = isr->saidx.reqid; + + p += sizeof(*xisr); + bcopy(&isr->saidx.src, p, isr->saidx.src.ss_len); + p += isr->saidx.src.ss_len; + bcopy(&isr->saidx.dst, p, isr->saidx.dst.ss_len); + p += isr->saidx.src.ss_len; + + xisr->sadb_x_ipsecrequest_len = + PFKEY_ALIGN8(sizeof(*xisr) + + isr->saidx.src.ss_len + + isr->saidx.dst.ss_len); } } - return xpl; + return m; } /* @@ -1369,7 +1205,7 @@ key_sp2msg(sp) * from the user(?). * Adding to SP database, * and send - * + * * to the socket which was send. * * IN: mhp: pointer to the pointer to each header. @@ -1384,11 +1220,9 @@ key_spdadd(mhp) struct sadb_msg *msg0; struct sadb_address *src0, *dst0; struct sadb_x_policy *xpl0; - struct secindex idx; + struct secpolicyindex spidx; struct secpolicy *newsp; -#ifdef RESTRICTED_DIR - u_int dir; -#endif + int error; /* sanity check */ if (mhp == NULL || mhp[0] == NULL) @@ -1399,7 +1233,9 @@ key_spdadd(mhp) if (mhp[SADB_EXT_ADDRESS_SRC] == NULL || mhp[SADB_EXT_ADDRESS_DST] == NULL || mhp[SADB_X_EXT_POLICY] == NULL) { +#ifdef IPSEC_DEBUG printf("key_spdadd: invalid message is passed.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; } @@ -1409,78 +1245,66 @@ key_spdadd(mhp) xpl0 = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; /* make secindex */ - if (key_setsecidx(src0, dst0, &idx, 0)) { - msg0->sadb_msg_errno = EINVAL; - return NULL; - } + KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, + src0 + 1, + dst0 + 1, + src0->sadb_address_prefixlen, + dst0->sadb_address_prefixlen, + src0->sadb_address_proto, + &spidx); -#ifdef RESTRICTED_DIR /* checking the direciton. */ - dir = key_checkdir(&idx, NULL); - switch (dir) { - case SADB_X_DIR_INBOUND: - case SADB_X_DIR_BIDIRECT: - case SADB_X_DIR_OUTBOUND: - /* XXX What I do ? */ + switch (xpl0->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: break; - case SADB_X_DIR_INVALID: + default: +#ifdef IPSEC_DEBUG printf("key_spdadd: Invalid SP direction.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; - default: - panic("key_spdadd: unexpected direction %u", dir); } -#endif /* Is there SP in SPD ? */ -#ifdef RESTRICTED_DIR - if (key_getsp(&idx, dir)) { - printf("key_spdadd: a SPD entry exists already.\n"); - msg0->sadb_msg_errno = EEXIST; - return NULL; - } -#else - if (key_getsp(&idx)) { - printf("key_spdadd: a SPD entry exists already.\n"); - msg0->sadb_msg_errno = EEXIST; - return NULL; - } + newsp = key_getsp(&spidx); + if (newsp != NULL) { + key_freesp(newsp); +#ifdef IPSEC_DEBUG + printf("key_spdadd: a SP entry exists already.\n"); #endif + msg0->sadb_msg_errno = EEXIST; + return NULL; + } /* check policy */ /* key_spdadd() accepts DISCARD, NONE and IPSEC. */ if (xpl0->sadb_x_policy_type == IPSEC_POLICY_ENTRUST || xpl0->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { +#ifdef IPSEC_DEBUG printf("key_spdadd: Invalid policy type.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; } /* allocation new SP entry */ - if ((newsp = key_msg2sp(xpl0)) == NULL) { - msg0->sadb_msg_errno = ENOBUFS; + if ((newsp = key_msg2sp(xpl0, PFKEY_EXTLEN(xpl0), &error)) == NULL) { + msg0->sadb_msg_errno = error; return NULL; } - if (key_setsecidx(src0, dst0, &newsp->idx, 1)) { - msg0->sadb_msg_errno = EINVAL; - key_freesp(newsp); - return NULL; - } + KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, + src0 + 1, + dst0 + 1, + src0->sadb_address_prefixlen, + dst0->sadb_address_prefixlen, + src0->sadb_address_proto, + &newsp->spidx); - newsp->next = 0; newsp->refcnt = 1; /* do not reclaim until I say I do */ newsp->state = IPSEC_SPSTATE_ALIVE; - - /* - * By key_getinspointforsp(), searching SPD for the place where - * SP sould be inserted, and insert into sptree - */ -#ifdef RESTRICTED_DIR - key_insnode(&sptree[dir], key_getinspointforsp(newsp, dir), newsp); -#else - key_insnode(&sptree, key_getinspointforsp(newsp), newsp); -#endif + LIST_INSERT_HEAD(&sptree[newsp->spidx.dir], newsp, chain); { struct sadb_msg *newmsg; @@ -1495,7 +1319,9 @@ key_spdadd(mhp) KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) { +#ifdef IPSEC_DEBUG printf("key_spdadd: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } @@ -1506,9 +1332,14 @@ key_spdadd(mhp) newmsg->sadb_msg_len = PFKEY_UNIT64(len); p = (caddr_t)newmsg + sizeof(*msg0); - p = key_copysadbext(p, mhp[SADB_X_EXT_POLICY]); - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + /* + * reqid may had been updated at key_msg2sp() if reqid's + * range violation. + */ + p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]); + + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); return newmsg; } @@ -1517,11 +1348,12 @@ key_spdadd(mhp) /* * SADB_SPDDELETE processing * receive - * + * * from the user(?), and set SADB_SASTATE_DEAD, * and send, - * + * * to the ikmpd. + * policy(*) including direction of policy. * * IN: mhp: pointer to the pointer to each header. * OUT: other if success, return pointer to the message to send. @@ -1533,11 +1365,9 @@ key_spddelete(mhp) { struct sadb_msg *msg0; struct sadb_address *src0, *dst0; - struct secindex idx; + struct sadb_x_policy *xpl0; + struct secpolicyindex spidx; struct secpolicy *sp; -#ifdef RESTRICTED_DIR - u_int dir; -#endif /* sanity check */ if (mhp == NULL || mhp[0] == NULL) @@ -1546,55 +1376,52 @@ key_spddelete(mhp) msg0 = (struct sadb_msg *)mhp[0]; if (mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { +#ifdef IPSEC_DEBUG printf("key_spddelete: invalid message is passed.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; } src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + xpl0 = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; /* make secindex */ - if (key_setsecidx(src0, dst0, &idx, 0)) { - msg0->sadb_msg_errno = EINVAL; - return NULL; - } + KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, + src0 + 1, + dst0 + 1, + src0->sadb_address_prefixlen, + dst0->sadb_address_prefixlen, + src0->sadb_address_proto, + &spidx); -#ifdef RESTRICTED_DIR /* checking the direciton. */ - dir = key_checkdir(&idx, NULL); - switch (dir) { - case SADB_X_DIR_INBOUND: - case SADB_X_DIR_BIDIRECT: - case SADB_X_DIR_OUTBOUND: - /* XXX What I do ? */ + switch (xpl0->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: break; - case SADB_X_DIR_INVALID: - printf("key_spddelete: Invalid SA direction.\n"); + default: +#ifdef IPSEC_DEBUG + printf("key_spddelete: Invalid SP direction.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; - default: - panic("key_spddelete: unexpected direction %u", dir); } -#endif /* Is there SP in SPD ? */ -#ifdef RESTRICTED_DIR - if ((sp = key_getsp(&idx, dir)) == NULL) { + if ((sp = key_getsp(&spidx)) == NULL) { +#ifdef IPSEC_DEBUG printf("key_spddelete: no SP found.\n"); - msg0->sadb_msg_errno = ENOENT; - return NULL; - } -#else - if ((sp = key_getsp(&idx)) == NULL) { - printf("key_spddelete: no SP found.\n"); - msg0->sadb_msg_errno = ENOENT; - return NULL; - } #endif + msg0->sadb_msg_errno = ENOENT; + return NULL; + } sp->state = IPSEC_SPSTATE_DEAD; + key_freesp(sp); { struct sadb_msg *newmsg; @@ -1603,12 +1430,15 @@ key_spddelete(mhp) /* create new sadb_msg to reply. */ len = sizeof(struct sadb_msg) + + PFKEY_EXTLEN(mhp[SADB_X_EXT_POLICY]) + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) { +#ifdef IPSEC_DEBUG printf("key_spddelete: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } @@ -1619,8 +1449,9 @@ key_spddelete(mhp) newmsg->sadb_msg_len = PFKEY_UNIT64(len); p = (caddr_t)newmsg + sizeof(*msg0); - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); return newmsg; } @@ -1646,6 +1477,7 @@ key_spdflush(mhp) { struct sadb_msg *msg0; struct secpolicy *sp; + u_int dir; /* sanity check */ if (mhp == NULL || mhp[0] == NULL) @@ -1653,7 +1485,11 @@ key_spdflush(mhp) msg0 = (struct sadb_msg *)mhp[0]; - KEY_SPDBLOOP(sp->state = IPSEC_SPSTATE_DEAD;); + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + LIST_FOREACH(sp, &sptree[dir], chain) { + sp->state = IPSEC_SPSTATE_DEAD; + } + } { struct sadb_msg *newmsg; @@ -1664,7 +1500,9 @@ key_spdflush(mhp) KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) { +#ifdef IPSEC_DEBUG printf("key_spdflush: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } @@ -1699,8 +1537,9 @@ key_spddump(mhp, so, target) { struct sadb_msg *msg0; struct secpolicy *sp; - int len, cnt, cnt_sanity; - struct sadb_msg *newmsg; + int cnt; + u_int dir; + struct mbuf *m; /* sanity check */ if (mhp == NULL || mhp[0] == NULL) @@ -1709,105 +1548,116 @@ key_spddump(mhp, so, target) msg0 = (struct sadb_msg *)mhp[0]; /* search SPD entry and get buffer size. */ - cnt = cnt_sanity = 0; - KEY_SPDBLOOP( - cnt++; - ); + cnt = 0; + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + LIST_FOREACH(sp, &sptree[dir], chain) { + cnt++; + } + } if (cnt == 0) return ENOENT; - newmsg = NULL; - KEY_SPDBLOOP( - len = key_getspmsglen(sp); + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + LIST_FOREACH(sp, &sptree[dir], chain) { + --cnt; + m = key_setdumpsp(sp, SADB_X_SPDDUMP, + cnt, msg0->sadb_msg_pid); - /* making buffer */ - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { - printf("key_spddump: No more memory.\n"); - return ENOBUFS; + if (m) + key_sendup_mbuf(so, m, target); } - bzero((caddr_t)newmsg, len); - - (void)key_setdumpsp(sp, newmsg); - newmsg->sadb_msg_type = SADB_X_SPDDUMP; - newmsg->sadb_msg_seq = --cnt; - newmsg->sadb_msg_pid = msg0->sadb_msg_pid; - - key_sendup(so, newmsg, len, target); - KFREE(newmsg); - newmsg = NULL; - ); + } return 0; } -static u_int -key_setdumpsp(sp, newmsg) +static struct mbuf * +key_setdumpsp(sp, type, seq, pid) struct secpolicy *sp; - struct sadb_msg *newmsg; + u_int8_t type; + u_int32_t seq, pid; { + struct mbuf *m; u_int tlen; - caddr_t p; - newmsg->sadb_msg_version = PF_KEY_V2; - newmsg->sadb_msg_satype = SADB_SATYPE_UNSPEC; /* XXX */; - newmsg->sadb_msg_errno = 0; - { - /* XXX this is DEBUG use. */ - caddr_t x = (caddr_t)&newmsg->sadb_msg_reserved; - -#ifdef RESTRICTED_DIR - for (x[0] = 0; x[0] < _ARRAYLEN(saorder_dir_any); x[0]++) { - if (sp->spt == &sptree[saorder_dir_any[(int)x[0]]]) - break; - } -#else - x[0] = 0; -#endif - - x[1] = sp->refcnt; - } + /* XXX it would be better to avoid pre-computing length */ tlen = key_getspmsglen(sp); - newmsg->sadb_msg_len = PFKEY_UNIT64(tlen); - p = (caddr_t)newmsg; - p += sizeof(struct sadb_msg); + /* XXX maybe it's a wrong idea to insist on cluster? */ + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m != NULL) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + m = NULL; + } + } + if (m == NULL) + return NULL; /*ENOBUFS*/ - p = key_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, - sp->idx.family, - (caddr_t)&sp->idx.src, - sp->idx.prefs, - sp->idx.proto, - sp->idx.ports); + m->m_pkthdr.len = m->m_len = 0; + m->m_next = NULL; - p = key_setsadbaddr(p, SADB_EXT_ADDRESS_DST, - sp->idx.family, - (caddr_t)&sp->idx.dst, - sp->idx.prefd, - sp->idx.proto, - sp->idx.portd); + /* sadb_msg->sadb_msg_len must be filled afterwards */ + if (key_setsadbmsg_m(m, type, 0, SADB_SATYPE_UNSPEC, seq, pid, + IPSEC_MODE_ANY, 0, 0, sp->refcnt) != 0) { + m_freem(m); + return NULL; + } + + if (key_setsadbaddr_m(m, SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sp->spidx.src, sp->spidx.prefs, + sp->spidx.ul_proto) != 0) { + m_freem(m); + return NULL; + } + + if (key_setsadbaddr_m(m, SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sp->spidx.dst, sp->spidx.prefd, + sp->spidx.ul_proto) != 0) { + m_freem(m); + return NULL; + } { + struct mbuf *n; struct sadb_x_policy *tmp; - if ((tmp = key_sp2msg(sp)) == NULL) { + n = key_sp2msg(sp); + if (!n || n->m_len < sizeof(*tmp)) { +#ifdef IPSEC_DEBUG printf("key_setdumpsp: No more memory.\n"); - return ENOBUFS; +#endif + m_freem(m); + if (n) + m_freem(n); + return NULL; } + tmp = mtod(n, struct sadb_x_policy *); + /* validity check */ - if (key_getspreqmsglen(sp) != PFKEY_UNUNIT64(tmp->sadb_x_policy_len)) + if (key_getspreqmsglen(sp) != PFKEY_UNUNIT64(tmp->sadb_x_policy_len) + || n->m_len != PFKEY_UNUNIT64(tmp->sadb_x_policy_len)) panic("key_setdumpsp: length mismatch." "sp:%d msg:%d\n", key_getspreqmsglen(sp), PFKEY_UNUNIT64(tmp->sadb_x_policy_len)); - bcopy(tmp, p, PFKEY_UNUNIT64(tmp->sadb_x_policy_len)); - KFREE(tmp); + m_cat(m, n); + m->m_pkthdr.len += n->m_len; } - return tlen; + if (m->m_len < sizeof(struct sadb_msg)) { + m = m_pullup(m, sizeof(struct sadb_msg)); + if (m == NULL) + return NULL; + } + mtod(m, struct sadb_msg *)->sadb_msg_len = + PFKEY_UNIT64(m->m_pkthdr.len); + + return m; } /* get sadb message length for a SP. */ @@ -1823,15 +1673,18 @@ key_getspmsglen(sp) tlen = (sizeof(struct sadb_msg) + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(sp->idx.family)) + + PFKEY_ALIGN8(_SALENBYAF(sp->spidx.src.ss_family)) + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(sp->idx.family))); + + PFKEY_ALIGN8(_SALENBYAF(sp->spidx.dst.ss_family))); tlen += key_getspreqmsglen(sp); return tlen; } +/* + * get PFKEY message length for security policy and request. + */ static u_int key_getspreqmsglen(sp) struct secpolicy *sp; @@ -1850,13 +1703,10 @@ key_getspreqmsglen(sp) int len; for (isr = sp->req; isr != NULL; isr = isr->next) { - len = sizeof(struct sadb_x_ipsecrequest); + len = sizeof(struct sadb_x_ipsecrequest) + + isr->saidx.src.ss_len + + isr->saidx.dst.ss_len; - /* if tunnel mode ? */ - if (isr->mode == IPSEC_MODE_TUNNEL - && isr->proxy != NULL) { - len += isr->proxy->sa_len; - } tlen += PFKEY_ALIGN8(len); } } @@ -1866,144 +1716,50 @@ key_getspreqmsglen(sp) /* %%% SAD management */ /* - * set sadb_address parameters into secindex buffer. - * Must allocate secindex buffer passed to this function. - * IN: flag == 0: copy pointer. - * == 1: with memory allocation for addresses and copy. - * So must call key_delsecidx() later. - * OUT: 0: success - * 1: failure - */ -int -key_setsecidx(src0, dst0, idx, flag) - struct sadb_address *src0, *dst0; - struct secindex *idx; - int flag; -{ - struct sockaddr *src, *dst; - - /* sanity check */ - if (src0 == NULL || dst0 == NULL || idx == NULL) - panic("key_setsecidx: NULL pointer is passed.\n"); - - src = (struct sockaddr *)((caddr_t)src0 + sizeof(*src0)); - dst = (struct sockaddr *)((caddr_t)dst0 + sizeof(*dst0)); - - /* check sa_family */ - if (src->sa_family != dst->sa_family) { - printf("key_setsecidx: family mismatch.\n"); - return 1; - } - - /* check max prefixlen */ - if ((_INALENBYAF(src->sa_family) << 3) < src0->sadb_address_prefixlen - || (_INALENBYAF(dst->sa_family) << 3) < dst0->sadb_address_prefixlen) { - printf("key_setsecidx: illegal prefixlen.\n"); - return 1; - } - - /* check protocol */ - if (src0->sadb_address_proto != dst0->sadb_address_proto) { - printf("key_setsecidx: protocol mismatch.\n"); - return 1; - } - - bzero((caddr_t)idx, sizeof(*idx)); - idx->family = src->sa_family; - idx->prefs = src0->sadb_address_prefixlen; - idx->prefd = dst0->sadb_address_prefixlen; - - /* initialize */ - bzero(&idx->src, sizeof(idx->src)); - bzero(&idx->dst, sizeof(idx->dst)); - - bcopy(_INADDRBYSA(src), &idx->src, _INALENBYAF(src->sa_family)); - bcopy(_INADDRBYSA(dst), &idx->dst, _INALENBYAF(dst->sa_family)); - idx->proto = src0->sadb_address_proto; - idx->ports = _INPORTBYSA(src); - idx->portd = _INPORTBYSA(dst); - - return 0; -} - -/* - * delete secindex - */ -void -key_delsecidx(idx) - struct secindex *idx; -{ - /* nothing to do */ - return; -} - -/* - * allocating a memory for new SA index, and copy from the values of mhp. + * allocating a memory for new SA head, and copy from the values of mhp. * OUT: NULL : failure due to the lack of memory. - * others : pointer to new SA index leaf. + * others : pointer to new SA head. */ -static struct secasindex * -#ifdef RESTRICTED_DIR -key_newsaidx(idx, dir) - struct secindex *idx; - u_int dir; -#else -key_newsaidx(idx) - struct secindex *idx; -#endif +static struct secashead * +key_newsah(saidx) + struct secasindex *saidx; { - struct secasindex *newsaidx = NULL; + struct secashead *newsah; /* sanity check */ - if (idx == NULL) + if (saidx == NULL) panic("key_newsaidx: NULL pointer is passed.\n"); - KMALLOC(newsaidx, struct secasindex *, sizeof(struct secasindex)); - if (newsaidx == NULL) { + newsah = keydb_newsecashead(); + if (newsah == NULL) return NULL; - } - bzero((caddr_t)newsaidx, sizeof(struct secasindex)); - newsaidx->idx.family = idx->family; - newsaidx->idx.prefs = idx->prefs; - newsaidx->idx.prefd = idx->prefd; - newsaidx->idx.proto = idx->proto; - newsaidx->idx.ports = idx->ports; - newsaidx->idx.portd = idx->portd; - - bcopy(&idx->src, &newsaidx->idx.src, _INALENBYAF(idx->family)); - bcopy(&idx->dst, &newsaidx->idx.dst, _INALENBYAF(idx->family)); + bcopy(saidx, &newsah->saidx, sizeof(newsah->saidx)); /* add to saidxtree */ -#ifdef RESTRICTED_DIR - key_insnode(&saidxtree[dir], NULL, newsaidx); -#else - key_insnode(&saidxtree, NULL, newsaidx); -#endif + newsah->state = SADB_SASTATE_MATURE; + LIST_INSERT_HEAD(&sahtree, newsah, chain); - return(newsaidx); + return(newsah); } /* * delete SA index and all SA registerd. */ static void -key_delsaidx(saidx) - struct secasindex *saidx; +key_delsah(sah) + struct secashead *sah; { - struct secas *sa, *nextsa; + struct secasvar *sav, *nextsav; u_int stateidx, state; int s; + int zombie = 0; /* sanity check */ - if (saidx == NULL) - panic("key_delsaidx: NULL pointer is passed.\n"); + if (sah == NULL) + panic("key_delsah: NULL pointer is passed.\n"); -#ifdef __NetBSD__ s = splsoftnet(); /*called from softclock()*/ -#else - s = splnet(); /*called from softclock()*/ -#endif /* searching all SA registerd in the secindex. */ for (stateidx = 0; @@ -2011,342 +1767,255 @@ key_delsaidx(saidx) stateidx++) { state = saorder_state_any[stateidx]; - for (sa = (struct secas *)saidx->satree[state].head; - sa != NULL; - sa = nextsa) { - nextsa = sa->next; + for (sav = (struct secasvar *)LIST_FIRST(&sah->savtree[state]); + sav != NULL; + sav = nextsav) { - /* sanity check */ - if (sa->state != state) { - printf("key_delsaidx: " - "invalid sa->state " - "(queue: %d SA: %d)\n", - state, sa->state); + nextsav = LIST_NEXT(sav, chain); + + if (sav->refcnt > 0) { + /* give up to delete this sa */ + zombie++; continue; } - /* remove back pointer */ - sa->saidx = NULL; - if (sa->refcnt < 0) { - printf("key_delsaidx: why refcnt < 0 ?, " - "sa->refcnt=%d\n", - sa->refcnt); - } - key_freesa(sa); - sa = NULL; + /* sanity check */ + KEY_CHKSASTATE(state, sav->state, "key_delsah"); + + key_freesav(sav); + + /* remove back pointer */ + sav->sah = NULL; + sav = NULL; } } - /* remove from tree of SA index */ - if (saidx->saidxt != NULL) - key_remnode(saidx); - - key_delsecidx(&saidx->idx); - - if (saidx->sa_route.ro_rt) { - RTFREE(saidx->sa_route.ro_rt); - saidx->sa_route.ro_rt = (struct rtentry *)NULL; + /* don't delete sah only if there are savs. */ + if (zombie) { + splx(s); + return; } - KFREE(saidx); + if (sah->sa_route.ro_rt) { + RTFREE(sah->sa_route.ro_rt); + sah->sa_route.ro_rt = (struct rtentry *)NULL; + } + + /* remove from tree of SA index */ + if (__LIST_CHAINED(sah)) + LIST_REMOVE(sah, chain); + + KFREE(sah); splx(s); return; } /* - * allocating a new SA for LARVAL state. key_add() and key_getspi() call, + * allocating a new SA with LARVAL state. key_add() and key_getspi() call, * and copy the values of mhp into new buffer. - * When SADB message type is GETSPI: + * When SAD message type is GETSPI: * to set sequence number from acq_seq++, * to set zero to SPI. * not to call key_setsava(). * OUT: NULL : fail - * others : pointer to new secas leaf. + * others : pointer to new secasvar. */ -static struct secas * -key_newsa(mhp, saidx) +static struct secasvar * +key_newsav(mhp, sah) caddr_t *mhp; - struct secasindex *saidx; + struct secashead *sah; { - struct secas *newsa; + struct secasvar *newsav; struct sadb_msg *msg0; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL || saidx == NULL) + if (mhp == NULL || mhp[0] == NULL || sah == NULL) panic("key_newsa: NULL pointer is passed.\n"); msg0 = (struct sadb_msg *)mhp[0]; - KMALLOC(newsa, struct secas *, sizeof(struct secas)); - if (newsa == NULL) { + KMALLOC(newsav, struct secasvar *, sizeof(struct secasvar)); + if (newsav == NULL) { +#ifdef IPSEC_DEBUG printf("key_newsa: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } - bzero((caddr_t)newsa, sizeof(struct secas)); + bzero((caddr_t)newsav, sizeof(struct secasvar)); switch (msg0->sadb_msg_type) { case SADB_GETSPI: - newsa->spi = 0; + newsav->spi = 0; +#ifdef IPSEC_DOSEQCHECK /* sync sequence number */ if (msg0->sadb_msg_seq == 0) - newsa->seq = + newsav->seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); else - newsa->seq = msg0->sadb_msg_seq; +#endif + newsav->seq = msg0->sadb_msg_seq; break; case SADB_ADD: /* sanity check */ - if (mhp[SADB_EXT_SA] == 0) { - KFREE(newsa); + if (mhp[SADB_EXT_SA] == NULL) { + KFREE(newsav); +#ifdef IPSEC_DEBUG printf("key_newsa: invalid message is passed.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; } - newsa->spi = ((struct sadb_sa *)mhp[SADB_EXT_SA])->sadb_sa_spi; - newsa->seq = msg0->sadb_msg_seq; + newsav->spi = ((struct sadb_sa *)mhp[SADB_EXT_SA])->sadb_sa_spi; + newsav->seq = msg0->sadb_msg_seq; break; default: - KFREE(newsa); + KFREE(newsav); msg0->sadb_msg_errno = EINVAL; return NULL; } - newsa->refcnt = 1; - newsa->type = msg0->sadb_msg_satype; - newsa->pid = msg0->sadb_msg_pid; - newsa->state = SADB_SASTATE_LARVAL; - newsa->saidx = saidx; + /* copy sav values */ + if (msg0->sadb_msg_type != SADB_GETSPI && key_setsaval(newsav, mhp)) { + KFREE(newsav); + /* msg0->sadb_msg_errno is set at key_setsaval. */ + return NULL; + } /* reset tick */ - newsa->tick = 0; + newsav->tick = 0; - /* copy sa values */ - if (msg0->sadb_msg_type != SADB_GETSPI && key_setsaval(newsa, mhp)) { - key_freesa(newsa); - return NULL; - } + newsav->pid = msg0->sadb_msg_pid; /* add to satree */ - key_insnode(&saidx->satree[SADB_SASTATE_LARVAL], NULL, newsa); + newsav->sah = sah; + newsav->refcnt = 1; + newsav->state = SADB_SASTATE_LARVAL; + LIST_INSERT_TAIL(&sah->savtree[SADB_SASTATE_LARVAL], newsav, + secasvar, chain); - return newsa; + return newsav; } -#if 0 -static struct secas * -key_newsa2(type, saidx) - u_int type; - struct secasindex *saidx; -{ - struct secas *newsa; - - /* sanity check */ - if (saidx == NULL) - panic("key_newsa2: NULL pointer is passed.\n"); - - KMALLOC(newsa, struct secas *, sizeof(struct secas)); - if (newsa == NULL) { - printf("key_newsa2: No more memory.\n"); - return NULL; - } - bzero((caddr_t)newsa, sizeof(struct secas)); - - /* set sequence */ - newsa->refcnt = 1; - newsa->state = SADB_SASTATE_LARVAL; - newsa->type = type; - newsa->spi = 0; - newsa->seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); - newsa->pid = 0; - newsa->saidx = saidx; - - /* add to satree */ - key_insnode(&saidx->satree[newsa->state], NULL, newsa); - - return newsa; -} -#endif - /* - * free() SA entry. + * free() SA variable entry. */ static void -key_delsa(sa) - struct secas *sa; +key_delsav(sav) + struct secasvar *sav; { /* sanity check */ - if (sa == NULL) - panic("key_delsa: NULL pointer is passed.\n"); + if (sav == NULL) + panic("key_delsav: NULL pointer is passed.\n"); - if (sa->refcnt > 0) return; /* can't free */ + if (sav->refcnt > 0) + return; /* can't free */ - /* remove from SA index */ - if (sa->sat != NULL) - key_remnode(sa); + /* remove from SA header */ + if (__LIST_CHAINED(sav)) + LIST_REMOVE(sav, chain); - if (sa->key_auth != NULL) - KFREE(sa->key_auth); - if (sa->key_enc != NULL) - KFREE(sa->key_enc); - if (sa->proxy != NULL) - KFREE(sa->proxy); - if (sa->replay != NULL) { - if (sa->replay->bitmap != NULL) - KFREE(sa->replay->bitmap); - KFREE(sa->replay); - } - if (sa->lft_c != NULL) - KFREE(sa->lft_c); - if (sa->lft_h != NULL) - KFREE(sa->lft_h); - if (sa->lft_s != NULL) - KFREE(sa->lft_s); - if (sa->iv != NULL) - KFREE(sa->iv); - if (sa->misc1 != NULL) - KFREE(sa->misc1); - if (sa->misc2 != NULL) - KFREE(sa->misc2); - if (sa->misc3 != NULL) - KFREE(sa->misc3); + if (sav->key_auth != NULL) + KFREE(sav->key_auth); + if (sav->key_enc != NULL) + KFREE(sav->key_enc); + if (sav->replay != NULL) + keydb_delsecreplay(sav->replay); + if (sav->lft_c != NULL) + KFREE(sav->lft_c); + if (sav->lft_h != NULL) + KFREE(sav->lft_h); + if (sav->lft_s != NULL) + KFREE(sav->lft_s); + if (sav->iv != NULL) + KFREE(sav->iv); +#if notyet + if (sav->misc1 != NULL) + KFREE(sav->misc1); + if (sav->misc2 != NULL) + KFREE(sav->misc2); + if (sav->misc3 != NULL) + KFREE(sav->misc3); +#endif - KFREE(sa); + KFREE(sav); return; } /* - * search SADB specified the direction for a SA index entry. + * search SAD. * OUT: * NULL : not found * others : found, pointer to a SA. */ -static struct secasindex * -#ifdef RESTRICTED_DIR -key_getsaidx(idx, dir) - struct secindex *idx; - u_int dir; -#else -key_getsaidx(idx) - struct secindex *idx; -#endif -{ +static struct secashead * +key_getsah(saidx) struct secasindex *saidx; +{ + struct secashead *sah; -#ifdef RESTRICTED_DIR - for (saidx = (struct secasindex *)saidxtree[dir].head; - saidx != NULL; - saidx = saidx->next) { - - if (key_cmpidx(&saidx->idx, idx)) - return(saidx); + LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_exactly(&sah->saidx, saidx)) + return(sah); } -#else - for (saidx = (struct secasindex *)saidxtree.head; - saidx != NULL; - saidx = saidx->next) { - - if (key_cmpidx(&saidx->idx, idx)) - return(saidx); - } -#endif return NULL; } /* - * search SADB in any direction for a SA index entry. + * check not to be duplicated SPI. + * NOTE: this function is too slow due to searching all SAD. * OUT: * NULL : not found * others : found, pointer to a SA. */ -static struct secasindex * -key_getsaidxfromany(idx) - struct secindex *idx; -{ +static struct secasvar * +key_checkspidup(saidx, spi) struct secasindex *saidx; -#ifdef RESTRICTED_DIR - u_int diridx; -#endif - -#ifdef RESTRICTED_DIR - for (diridx = 0; diridx < _ARRAYLEN(saorder_dir_any); diridx++) { - - saidx = key_getsaidx(idx, saorder_dir_any[diridx]); - if (saidx != NULL) - return(saidx); - } -#else - saidx = key_getsaidx(idx); - if (saidx != NULL) - return(saidx); -#endif - - return NULL; -} - -/* - * check the dupulication of SPI by searching only INBOUND SADB. - * OUT: - * NULL : not found - * others : found, pointer to a SA. - */ -static struct secas * -key_checkspi(spi, proto) - u_int32_t spi; - u_int proto; -{ - struct secasindex *saidx; -#ifdef RESTRICTED_DIR - u_int diridx, dir; -#endif - struct secas *sa; - - /* check all status of INBOUND SADB. */ -#ifdef RESTRICTED_DIR - for (diridx = 0; diridx < _ARRAYLEN(saorder_dir_input); diridx++) { - - dir = saorder_dir_input[diridx]; - for (saidx = (struct secasindex *)saidxtree[dir].head; - saidx != NULL; - saidx = saidx->next) { - - sa = key_getsabyspi(saidx, proto, spi); - if (sa != NULL) - return sa; - } - } -#else - for (saidx = (struct secasindex *)saidxtree.head; - saidx != NULL; - saidx = saidx->next) { - - sa = key_getsabyspi(saidx, proto, spi); - if (sa != NULL) - return sa; - } -#endif - - return NULL; -} - -/* - * search SADB limited to alive SA with direction, protocol, SPI. - * OUT: - * NULL : not found - * others : found, pointer to a SA. - */ -static struct secas * -key_getsabyspi(saidx, proto, spi) - struct secasindex *saidx; - u_int proto; u_int32_t spi; { - struct secas *sa; + struct secashead *sah; + struct secasvar *sav; + + /* check address family */ + if (saidx->src.ss_family != saidx->dst.ss_family) { +#ifdef IPSEC_DEBUG + printf("key_checkspidup: address family mismatched.\n"); +#endif + return NULL; + } + + /* check all SAD */ + LIST_FOREACH(sah, &sahtree, chain) { + if (!key_ismyaddr(sah->saidx.dst.ss_family, + _INADDRBYSA(&sah->saidx.dst))) + continue; + sav = key_getsavbyspi(sah, spi); + if (sav != NULL) + return sav; + } + + return NULL; +} + +/* + * search SAD litmited alive SA, protocol, SPI. + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secasvar * +key_getsavbyspi(sah, spi) + struct secashead *sah; + u_int32_t spi; +{ + struct secasvar *sav; u_int stateidx, state; /* search all status */ @@ -2355,23 +2024,21 @@ key_getsabyspi(saidx, proto, spi) stateidx++) { state = saorder_state_alive[stateidx]; - for (sa = (struct secas *)saidx->satree[state].head; - sa != NULL; - sa = sa->next) { + LIST_FOREACH(sav, &sah->savtree[state], chain) { /* sanity check */ - if (sa->state != state) { - printf("key_getsabyspi: " - "invalid sa->state " + if (sav->state != state) { +#ifdef IPSEC_DEBUG + printf("key_getsavbyspi: " + "invalid sav->state " "(queue: %d SA: %d)\n", - state, sa->state); + state, sav->state); +#endif continue; } - if (sa->type != proto) - continue; - if (sa->spi == spi) - return sa; + if (sav->spi == spi) + return sav; } } @@ -2381,13 +2048,12 @@ key_getsabyspi(saidx, proto, spi) /* * copy SA values from PF_KEY message except *SPI, SEQ, PID, STATE and TYPE*. * You must update these if need. - * NOTE: When error occured in this function, we *FREE* sa passed. * OUT: 0: success. * 1: failure. set errno to (mhp[0])->sadb_msg_errno. */ static int -key_setsaval(sa, mhp) - struct secas *sa; +key_setsaval(sav, mhp) + struct secasvar *sav; caddr_t *mhp; { struct sadb_msg *msg0; @@ -2400,64 +2066,34 @@ key_setsaval(sa, mhp) msg0 = (struct sadb_msg *)mhp[0]; /* initialization */ - sa->key_auth = NULL; - sa->key_enc = NULL; - sa->proxy = NULL; - sa->replay = NULL; - sa->lft_c = NULL; - sa->lft_h = NULL; - sa->lft_s = NULL; - sa->iv = NULL; - sa->misc1 = NULL; - sa->misc2 = NULL; - sa->misc3 = NULL; + sav->replay = NULL; + sav->key_auth = NULL; + sav->key_enc = NULL; + sav->iv = NULL; + sav->lft_c = NULL; + sav->lft_h = NULL; + sav->lft_s = NULL; +#if notyet + sav->misc1 = NULL; + sav->misc2 = NULL; + sav->misc3 = NULL; +#endif /* SA */ if (mhp[SADB_EXT_SA] != NULL) { struct sadb_sa *sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; - sa->alg_auth = sa0->sadb_sa_auth; - sa->alg_enc = sa0->sadb_sa_encrypt; - sa->flags = sa0->sadb_sa_flags; + sav->alg_auth = sa0->sadb_sa_auth; + sav->alg_enc = sa0->sadb_sa_encrypt; + sav->flags = sa0->sadb_sa_flags; /* replay window */ if ((sa0->sadb_sa_flags & SADB_X_EXT_OLD) == 0) { - KMALLOC(sa->replay, struct secreplay *, - sizeof(struct secreplay)); - if (sa->replay == NULL) { - printf("key_setsaval: No more memory.\n"); - error = ENOBUFS; - goto err; - } - bzero(sa->replay, sizeof(struct secreplay)); - - if ((sa->replay->wsize = sa0->sadb_sa_replay) != 0) { - KMALLOC(sa->replay->bitmap, caddr_t, - sa->replay->wsize); - if (sa->replay->bitmap == NULL) { - printf("key_setsaval: " - "No more memory.\n"); - error = ENOBUFS; - goto err; - } - bzero(sa->replay->bitmap, sa0->sadb_sa_replay); - } - } - } - - /* Proxy address */ - if (mhp[SADB_EXT_ADDRESS_PROXY] != NULL) { - struct sockaddr *proxy; - - proxy = (struct sockaddr *)(mhp[SADB_EXT_ADDRESS_PROXY] - + sizeof(struct sadb_address)); - - /* copy proxy if exists. */ - if (proxy != NULL) { - KEY_NEWBUF(sa->proxy, struct sockaddr *, - proxy, proxy->sa_len); - if (sa->proxy == NULL) { + sav->replay = keydb_newsecreplay(sa0->sadb_sa_replay); + if (sav->replay == NULL) { +#ifdef IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); +#endif error = ENOBUFS; goto err; } @@ -2479,7 +2115,7 @@ key_setsaval(sa, mhp) case SADB_SATYPE_AH: case SADB_SATYPE_ESP: if (len == sizeof(struct sadb_key) - && sa->alg_auth != SADB_AALG_NULL) { + && sav->alg_auth != SADB_AALG_NULL) { error = EINVAL; } break; @@ -2491,19 +2127,23 @@ key_setsaval(sa, mhp) break; } if (error) { +#ifdef IPSEC_DEBUG printf("key_setsaval: invalid key_auth values.\n"); +#endif goto err; } - KEY_NEWBUF(sa->key_auth, struct sadb_key *, key0, len); - if (sa->key_auth == NULL) { + sav->key_auth = (struct sadb_key *)key_newbuf(key0, len); + if (sav->key_auth == NULL) { +#ifdef IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); +#endif error = ENOBUFS; goto err; } /* make length shift up for kernel*/ - sa->key_auth->sadb_key_len = len; + sav->key_auth->sadb_key_len = len; } /* Encryption key */ @@ -2520,7 +2160,7 @@ key_setsaval(sa, mhp) switch (msg0->sadb_msg_satype) { case SADB_SATYPE_ESP: if (len == sizeof(struct sadb_key) - && sa->alg_enc != SADB_EALG_NULL) { + && sav->alg_enc != SADB_EALG_NULL) { error = EINVAL; } break; @@ -2534,36 +2174,42 @@ key_setsaval(sa, mhp) break; } if (error) { +#ifdef IPSEC_DEBUG printf("key_setsatval: invalid key_enc value.\n"); +#endif goto err; } - KEY_NEWBUF(sa->key_enc, struct sadb_key *, key0, len); - if (sa->key_enc == NULL) { + sav->key_enc = (struct sadb_key *)key_newbuf(key0, len); + if (sav->key_enc == NULL) { +#ifdef IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); +#endif error = ENOBUFS; goto err; } /* make length shift up for kernel*/ - sa->key_enc->sadb_key_len = len; + sav->key_enc->sadb_key_len = len; } - /* XXX: set iv */ - sa->ivlen = 0; + /* set iv */ + sav->ivlen = 0; - switch (sa->type) { + switch (msg0->sadb_msg_satype) { case SADB_SATYPE_ESP: #ifdef IPSEC_ESP { struct esp_algorithm *algo; - algo = &esp_algorithms[sa->alg_enc]; + algo = &esp_algorithms[sav->alg_enc]; if (algo && algo->ivlen) - sa->ivlen = (*algo->ivlen)(sa); - KMALLOC(sa->iv, caddr_t, sa->ivlen); - if (sa->iv == 0) { + sav->ivlen = (*algo->ivlen)(sav); + KMALLOC(sav->iv, caddr_t, sav->ivlen); + if (sav->iv == 0) { +#ifdef IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); +#endif error = ENOBUFS; goto err; } @@ -2579,35 +2225,39 @@ key_setsaval(sa, mhp) #endif break; default: +#ifdef IPSEC_DEBUG printf("key_setsaval: invalid SA type.\n"); +#endif error = EINVAL; goto err; } /* reset tick */ - sa->tick = 0; + sav->tick = 0; /* make lifetime for CURRENT */ { struct timeval tv; - KMALLOC(sa->lft_c, struct sadb_lifetime *, + KMALLOC(sav->lft_c, struct sadb_lifetime *, sizeof(struct sadb_lifetime)); - if (sa->lft_c == NULL) { + if (sav->lft_c == NULL) { +#ifdef IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); +#endif error = ENOBUFS; goto err; } microtime(&tv); - sa->lft_c->sadb_lifetime_len = + sav->lft_c->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); - sa->lft_c->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; - sa->lft_c->sadb_lifetime_allocations = 0; - sa->lft_c->sadb_lifetime_bytes = 0; - sa->lft_c->sadb_lifetime_addtime = tv.tv_sec; - sa->lft_c->sadb_lifetime_usetime = 0; + sav->lft_c->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; + sav->lft_c->sadb_lifetime_allocations = 0; + sav->lft_c->sadb_lifetime_bytes = 0; + sav->lft_c->sadb_lifetime_addtime = tv.tv_sec; + sav->lft_c->sadb_lifetime_usetime = 0; } /* lifetimes for HARD and SOFT */ @@ -2616,10 +2266,12 @@ key_setsaval(sa, mhp) lft0 = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; if (lft0 != NULL) { - KEY_NEWBUF(sa->lft_h, struct sadb_lifetime *, - lft0, sizeof(*lft0)); - if (sa->lft_h == NULL) { + sav->lft_h = (struct sadb_lifetime *)key_newbuf(lft0, + sizeof(*lft0)); + if (sav->lft_h == NULL) { +#ifdef IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); +#endif error = ENOBUFS; goto err; } @@ -2628,10 +2280,12 @@ key_setsaval(sa, mhp) lft0 = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; if (lft0 != NULL) { - KEY_NEWBUF(sa->lft_s, struct sadb_lifetime *, - lft0, sizeof(*lft0)); - if (sa->lft_s == NULL) { + sav->lft_s = (struct sadb_lifetime *)key_newbuf(lft0, + sizeof(*lft0)); + if (sav->lft_s == NULL) { +#ifdef IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); +#endif error = ENOBUFS; goto err; } @@ -2639,28 +2293,32 @@ key_setsaval(sa, mhp) } } -#if 0 +#if notyet /* pre-processing for DES */ - switch (sa->alg_enc) { + switch (sav->alg_enc) { case SADB_EALG_DESCBC: - if (des_key_sched((C_Block *)_KEYBUF(sa->key_enc), - (des_key_schedule)sa->misc1) != 0) { + if (des_key_sched((C_Block *)_KEYBUF(sav->key_enc), + (des_key_schedule)sav->misc1) != 0) { +#ifdef IPSEC_DEBUG printf("key_setsaval: error des_key_sched.\n"); - sa->misc1 = NULL; +#endif + sav->misc1 = NULL; /* THROUGH */ } break; case SADB_EALG_3DESCBC: - if (des_key_sched((C_Block *)_KEYBUF(sa->key_enc), - (des_key_schedule)sa->misc1) != 0 - || des_key_sched((C_Block *)(_KEYBUF(sa->key_enc) + 8), - (des_key_schedule)sa->misc2) != 0 - || des_key_sched((C_Block *)(_KEYBUF(sa->key_enc) + 16), - (des_key_schedule)sa->misc3) != 0) { + if (des_key_sched((C_Block *)_KEYBUF(sav->key_enc), + (des_key_schedule)sav->misc1) != 0 + || des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), + (des_key_schedule)sav->misc2) != 0 + || des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), + (des_key_schedule)sav->misc3) != 0) { +#ifdef IPSEC_DEBUG printf("key_setsaval: error des_key_sched.\n"); - sa->misc1 = NULL; - sa->misc2 = NULL; - sa->misc3 = NULL; +#endif + sav->misc1 = NULL; + sav->misc2 = NULL; + sav->misc3 = NULL; /* THROUGH */ } } @@ -2670,6 +2328,30 @@ key_setsaval(sa, mhp) return 0; err: + /* initialization */ + if (sav->replay != NULL) + keydb_delsecreplay(sav->replay); + if (sav->key_auth != NULL) + KFREE(sav->key_auth); + if (sav->key_enc != NULL) + KFREE(sav->key_enc); + if (sav->iv != NULL) + KFREE(sav->iv); + if (sav->lft_c != NULL) + KFREE(sav->lft_c); + if (sav->lft_h != NULL) + KFREE(sav->lft_h); + if (sav->lft_s != NULL) + KFREE(sav->lft_s); +#if notyet + if (sav->misc1 != NULL) + KFREE(sav->misc1); + if (sav->misc2 != NULL) + KFREE(sav->misc2); + if (sav->misc3 != NULL) + KFREE(sav->misc3); +#endif + msg0->sadb_msg_errno = error; return 1; } @@ -2678,45 +2360,40 @@ key_setsaval(sa, mhp) * get message buffer length. */ static u_int -key_getmsglen(sa) - struct secas *sa; +key_getmsglen(sav) + struct secasvar *sav; { int len = sizeof(struct sadb_msg); len += sizeof(struct sadb_sa); len += (sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(sa->saidx->idx.family))); + + PFKEY_ALIGN8(_SALENBYAF(sav->sah->saidx.src.ss_family))); len += (sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(sa->saidx->idx.family))); + + PFKEY_ALIGN8(_SALENBYAF(sav->sah->saidx.dst.ss_family))); - if (sa->key_auth != NULL) - len += sa->key_auth->sadb_key_len; - if (sa->key_enc != NULL) - len += sa->key_enc->sadb_key_len; + if (sav->key_auth != NULL) + len += sav->key_auth->sadb_key_len; + if (sav->key_enc != NULL) + len += sav->key_enc->sadb_key_len; - if (sa->proxy != NULL) { - len += (sizeof(struct sadb_address) - + PFKEY_ALIGN8(sa->proxy->sa_len)); - } - - if (sa->lft_c != NULL) + if (sav->lft_c != NULL) len += sizeof(struct sadb_lifetime); - if (sa->lft_h != NULL) + if (sav->lft_h != NULL) len += sizeof(struct sadb_lifetime); - if (sa->lft_s != NULL) + if (sav->lft_s != NULL) len += sizeof(struct sadb_lifetime); return len; } /* - * validation with a secas entry, and set SADB_SATYPE_MATURE. + * validation with a secasvar entry, and set SADB_SATYPE_MATURE. * OUT: 0: valid * other: errno */ static int -key_mature(sa) - struct secas *sa; +key_mature(sav) + struct secasvar *sav; { int mature; int checkmask = 0; /* 2^0: ealg 2^1: aalg 2^2: calg */ @@ -2725,44 +2402,61 @@ key_mature(sa) mature = 0; /* check SPI value */ - if (ntohl(sa->spi) >= 0 && ntohl(sa->spi) <= 255) { - printf("key_mature: illegal range of SPI %d.\n", sa->spi); + if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) { +#ifdef IPSEC_DEBUG + printf("key_mature: illegal range of SPI %d.\n", sav->spi); +#endif return EINVAL; } /* check satype */ - switch (sa->type) { - case SADB_SATYPE_ESP: + switch (sav->sah->saidx.proto) { + case IPPROTO_ESP: /* check flags */ - if ((sa->flags & SADB_X_EXT_OLD) && (sa->flags & SADB_X_EXT_DERIV)) { - printf("key_mature: invalid flag (derived) given to old-esp.\n"); + if ((sav->flags & SADB_X_EXT_OLD) + && (sav->flags & SADB_X_EXT_DERIV)) { +#ifdef IPSEC_DEBUG + printf("key_mature: " + "invalid flag (derived) given to old-esp.\n"); +#endif return EINVAL; } checkmask = 3; mustmask = 1; break; - case SADB_SATYPE_AH: + case IPPROTO_AH: /* check flags */ - if (sa->flags & SADB_X_EXT_DERIV) { - printf("key_mature: invalid flag (derived) given to AH SA.\n"); + if (sav->flags & SADB_X_EXT_DERIV) { +#ifdef IPSEC_DEBUG + printf("key_mature: " + "invalid flag (derived) given to AH SA.\n"); +#endif return EINVAL; } - if (sa->alg_enc != SADB_EALG_NONE) { - printf("key_mature: protocol and algorithm mismated.\n"); + if (sav->alg_enc != SADB_EALG_NONE) { +#ifdef IPSEC_DEBUG + printf("key_mature: " + "protocol and algorithm mismated.\n"); +#endif return(EINVAL); } checkmask = 2; mustmask = 2; break; #if 1 /*nonstandard*/ - case SADB_X_SATYPE_IPCOMP: - if (sa->alg_auth != SADB_AALG_NONE) { - printf("key_mature: protocol and algorithm mismated.\n"); + case IPPROTO_IPCOMP: + if (sav->alg_auth != SADB_AALG_NONE) { +#ifdef IPSEC_DEBUG + printf("key_mature: " + "protocol and algorithm mismated.\n"); +#endif return(EINVAL); } - if ((sa->flags & SADB_X_EXT_RAWCPI) == 0 - && ntohl(sa->spi) >= 0x10000) { + if ((sav->flags & SADB_X_EXT_RAWCPI) == 0 + && ntohl(sav->spi) >= 0x10000) { +#ifdef IPSEC_DEBUG printf("key_mature: invalid cpi for IPComp.\n"); +#endif return(EINVAL); } checkmask = 4; @@ -2770,7 +2464,9 @@ key_mature(sa) break; #endif default: +#ifdef IPSEC_DEBUG printf("key_mature: Invalid satype.\n"); +#endif return EPROTONOSUPPORT; } @@ -2780,7 +2476,7 @@ key_mature(sa) int keylen; /* XXX: should use algorithm map to check. */ - switch (sa->alg_auth) { + switch (sav->alg_auth) { case SADB_AALG_NONE: case SADB_AALG_MD5HMAC: case SADB_AALG_SHA1HMAC: @@ -2789,34 +2485,43 @@ key_mature(sa) case SADB_AALG_NULL: break; default: - printf("key_mature: unknown authentication algorithm.\n"); +#ifdef IPSEC_DEBUG + printf("key_mature: " + "unknown authentication algorithm.\n"); +#endif return EINVAL; } /* algorithm-dependent check */ - algo = &ah_algorithms[sa->alg_auth]; + algo = &ah_algorithms[sav->alg_auth]; - if (sa->key_auth) - keylen = sa->key_auth->sadb_key_bits; + if (sav->key_auth) + keylen = sav->key_auth->sadb_key_bits; else keylen = 0; if (keylen < algo->keymin || algo->keymax < keylen) { +#ifdef IPSEC_DEBUG printf("key_mature: invalid AH key length %d " "(%d-%d allowed)\n", keylen, algo->keymin, algo->keymax); +#endif return EINVAL; } if (algo->mature) { - if ((*algo->mature)(sa)) { - /* message generated in per-algorithm function */ + if ((*algo->mature)(sav)) { + /* message generated in per-algorithm function*/ return EINVAL; } else mature = SADB_SATYPE_AH; } - if ((mustmask & 2) != 0 && mature != SADB_SATYPE_AH) + if ((mustmask & 2) != 0 && mature != SADB_SATYPE_AH) { +#ifdef IPSEC_DEBUG + printf("key_mature: no satisfy algorithm for AH\n"); +#endif return EINVAL; + } } /* check encryption algorithm */ @@ -2825,7 +2530,7 @@ key_mature(sa) struct esp_algorithm *algo; int keylen; - switch (sa->alg_enc) { + switch (sav->alg_enc) { case SADB_EALG_NONE: case SADB_EALG_DESCBC: case SADB_EALG_3DESCBC: @@ -2837,36 +2542,46 @@ key_mature(sa) #endif break; default: +#ifdef IPSEC_DEBUG printf("key_mature: unknown encryption algorithm.\n"); - return(EINVAL); +#endif + return EINVAL; } /* algorithm-dependent check */ - algo = &esp_algorithms[sa->alg_enc]; + algo = &esp_algorithms[sav->alg_enc]; - if (sa->key_enc) - keylen = sa->key_enc->sadb_key_bits; + if (sav->key_enc) + keylen = sav->key_enc->sadb_key_bits; else keylen = 0; if (keylen < algo->keymin || algo->keymax < keylen) { +#ifdef IPSEC_DEBUG printf("key_mature: invalid ESP key length %d " "(%d-%d allowed)\n", keylen, algo->keymin, algo->keymax); +#endif return EINVAL; } if (algo->mature) { - if ((*algo->mature)(sa)) { - /* message generated in per-algorithm function */ + if ((*algo->mature)(sav)) { + /* message generated in per-algorithm function*/ return EINVAL; } else mature = SADB_SATYPE_ESP; } - if ((mustmask & 1) != 0 && mature != SADB_SATYPE_ESP) + if ((mustmask & 1) != 0 && mature != SADB_SATYPE_ESP) { +#ifdef IPSEC_DEBUG + printf("key_mature: no satisfy algorithm for ESP\n"); +#endif return EINVAL; -#else + } +#else /*IPSEC_ESP*/ +#ifdef IPSEC_DEBUG printf("key_mature: ESP not supported in this configuration\n"); +#endif return EINVAL; #endif } @@ -2875,37 +2590,32 @@ key_mature(sa) if ((checkmask & 4) != 0) { struct ipcomp_algorithm *algo; - switch (sa->alg_enc) { + switch (sav->alg_enc) { case SADB_X_CALG_NONE: case SADB_X_CALG_OUI: case SADB_X_CALG_DEFLATE: case SADB_X_CALG_LZS: break; default: +#ifdef IPSEC_DEBUG printf("key_mature: unknown compression algorithm.\n"); +#endif return EINVAL; } /* algorithm-dependent check */ - algo = &ipcomp_algorithms[sa->alg_enc]; + algo = &ipcomp_algorithms[sav->alg_enc]; if (!(algo->compress && algo->decompress)) { +#ifdef IPSEC_DEBUG printf("key_mature: " "unsupported compression algorithm.\n"); +#endif return EINVAL; } } -#if 0 /* not need */ - /* XXX: check flags */ - if ((sa->flags & SADB_X_EXT_PMASK) == SADB_X_EXT_PMASK) { - printf("key_mature: invalid padding flag = %u.\n", - sa->flags); - return(EINVAL); - } -#endif - - key_sa_chgstate(sa, SADB_SASTATE_MATURE); + key_sa_chgstate(sav, SADB_SASTATE_MATURE); return 0; } @@ -2915,92 +2625,51 @@ key_mature(sa) * the buf must be allocated sufficent space. */ static u_int -key_setdumpsa(sa, newmsg) - struct secas *sa; +key_setdumpsa(newmsg, sav, type, satype, seq, pid) struct sadb_msg *newmsg; + struct secasvar *sav; + u_int8_t type, satype; + u_int32_t seq, pid; { u_int tlen; caddr_t p; int i; - newmsg->sadb_msg_version = PF_KEY_V2; - newmsg->sadb_msg_satype = sa->type; - newmsg->sadb_msg_errno = 0; - { - /* XXX this is DEBUG use. */ - caddr_t x = (caddr_t)&newmsg->sadb_msg_reserved; + tlen = key_getmsglen(sav); -#ifdef RESTRICTED_DIR - for (x[0] = 0; x[0] < _ARRAYLEN(saorder_dir_any); x[0]++) { - if (sa->saidx->saidxt == &saidxtree[saorder_dir_any[(int)x[0]]]) - break; - } -#else - x[0] = (unsigned char)sa->seq; -#endif + p = key_setsadbmsg((caddr_t)newmsg, type, tlen, + satype, seq, pid, + sav->sah->saidx.mode, sav->sah->saidx.reqid, + 0, sav->refcnt); - x[1] = sa->refcnt; - } - tlen = key_getmsglen(sa); - newmsg->sadb_msg_len = PFKEY_UNIT64(tlen); - - p = (caddr_t)newmsg; - p += sizeof(struct sadb_msg); for (i = 1; i <= SADB_EXT_MAX; i++) { switch (i) { case SADB_EXT_SA: - { - struct sadb_sa sa0; - - sa0.sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa)); - sa0.sadb_sa_exttype = i; - sa0.sadb_sa_spi = sa->spi; - if (sa->replay) - sa0.sadb_sa_replay = sa->replay->wsize; - else - sa0.sadb_sa_replay = 0; - sa0.sadb_sa_state = sa->state; - sa0.sadb_sa_auth = sa->alg_auth; - sa0.sadb_sa_encrypt = sa->alg_enc; - sa0.sadb_sa_flags = sa->flags; - bcopy((caddr_t)&sa0, p, sizeof(sa0)); - p += sizeof(sa0); - } + p = key_setsadbsa(p, sav); break; case SADB_EXT_ADDRESS_SRC: - p = key_setsadbaddr(p, i, - sa->saidx->idx.family, - (caddr_t)&sa->saidx->idx.src, - sa->saidx->idx.prefs, - sa->saidx->idx.proto, - sa->saidx->idx.ports); + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sav->sah->saidx.src, + _INALENBYAF(sav->sah->saidx.src.ss_family) << 3, + IPSEC_ULPROTO_ANY); break; case SADB_EXT_ADDRESS_DST: - p = key_setsadbaddr(p, i, - sa->saidx->idx.family, - (caddr_t)&sa->saidx->idx.dst, - sa->saidx->idx.prefd, - sa->saidx->idx.proto, - sa->saidx->idx.portd); - break; - - case SADB_EXT_ADDRESS_PROXY: - if (sa->proxy == NULL) break; - p = key_setsadbaddr(p, i, - sa->proxy->sa_family, - _INADDRBYSA(sa->proxy), - _INALENBYAF(sa->proxy->sa_family) << 3, - 0, 0); + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sav->sah->saidx.dst, + _INALENBYAF(sav->sah->saidx.dst.ss_family) << 3, + IPSEC_ULPROTO_ANY); break; case SADB_EXT_KEY_AUTH: { u_int len; - if (sa->key_auth == NULL) break; - len = sa->key_auth->sadb_key_len; /* real length */ - bcopy((caddr_t)sa->key_auth, p, len); + if (sav->key_auth == NULL) break; + len = sav->key_auth->sadb_key_len; /* real length */ + bcopy((caddr_t)sav->key_auth, p, len); ((struct sadb_ext *)p)->sadb_ext_len = PFKEY_UNIT64(len); p += len; } @@ -3009,31 +2678,32 @@ key_setdumpsa(sa, newmsg) case SADB_EXT_KEY_ENCRYPT: { u_int len; - if (sa->key_enc == NULL) break; - len = sa->key_enc->sadb_key_len; /* real length */ - bcopy((caddr_t)sa->key_enc, p, len); + if (sav->key_enc == NULL) break; + len = sav->key_enc->sadb_key_len; /* real length */ + bcopy((caddr_t)sav->key_enc, p, len); ((struct sadb_ext *)p)->sadb_ext_len = PFKEY_UNIT64(len); p += len; } break;; case SADB_EXT_LIFETIME_CURRENT: - if (sa->lft_c == NULL) break; - p = key_copysadbext(p, (caddr_t)sa->lft_c); + if (sav->lft_c == NULL) break; + p = key_setsadbext(p, (caddr_t)sav->lft_c); break; case SADB_EXT_LIFETIME_HARD: - if (sa->lft_h == NULL) break; - p = key_copysadbext(p, (caddr_t)sa->lft_h); + if (sav->lft_h == NULL) break; + p = key_setsadbext(p, (caddr_t)sav->lft_h); break; case SADB_EXT_LIFETIME_SOFT: - if (sa->lft_s == NULL) break; - p = key_copysadbext(p, (caddr_t)sa->lft_s); + if (sav->lft_s == NULL) break; + p = key_setsadbext(p, (caddr_t)sav->lft_s); break; case SADB_EXT_IDENTITY_SRC: case SADB_EXT_IDENTITY_DST: + /* XXX: should we brought from SPD ? */ case SADB_EXT_SENSITIVITY: default: break; @@ -3043,85 +2713,204 @@ key_setdumpsa(sa, newmsg) return tlen; } -/* - * set SADB_SASTATE_DEAD to secindex's state if there is no SA registerd. - */ -static void -key_issaidx_dead(saidx) - struct secasindex *saidx; +#if 1 +static int +key_setsadbmsg_m(m, type, tlen, satype, seq, pid, mode, reqid, + reserved1, reserved2) + struct mbuf *m; + u_int8_t type, satype; + u_int16_t tlen; + u_int32_t seq; + pid_t pid; + u_int8_t mode; + u_int32_t reqid; + u_int8_t reserved1; + u_int32_t reserved2; { - u_int stateidx; - int count; + caddr_t p; + const size_t len = sizeof(struct sadb_msg); - /* sanity check */ - if (saidx == NULL) - panic("key_issaidx_dead: NULL pointer is passed.\n"); + p = key_appendmbuf(m, len); + if (p == NULL) + return ENOBUFS; - /* searching all SA registerd in the secindex. */ - count = 0; - for (stateidx = 0; - stateidx < _ARRAYLEN(saorder_state_any); - stateidx++) { - count += saidx->satree[saorder_state_any[stateidx]].len; - } + if (key_setsadbmsg(p, type, tlen, satype, seq, pid, mode, reqid, + reserved1, reserved2)) + return 0; + else + return EINVAL; +} +#endif - KEYDEBUG(KEYDEBUG_KEY_DATA, - printf("key_issaidx_dead: number of SA=%d\n", count)); +/* + * set data into sadb_msg. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbmsg(buf, type, tlen, satype, seq, pid, mode, reqid, + reserved1, reserved2) + caddr_t buf; + u_int8_t type, satype; + u_int16_t tlen; + u_int32_t seq; + pid_t pid; + u_int8_t mode; + u_int32_t reqid; + u_int8_t reserved1; + u_int32_t reserved2; +{ + struct sadb_msg *p; + u_int len; - if (count == 0) - key_delsaidx(saidx); + p = (struct sadb_msg *)buf; + len = sizeof(struct sadb_msg); - return; + bzero(p, len); + p->sadb_msg_version = PF_KEY_V2; + p->sadb_msg_type = type; + p->sadb_msg_errno = 0; + p->sadb_msg_satype = satype; + p->sadb_msg_len = PFKEY_UNIT64(tlen); + p->sadb_msg_mode = mode; + p->sadb_msg_reserved1 = reserved1; + p->sadb_msg_seq = seq; + p->sadb_msg_pid = (u_int32_t)pid; + p->sadb_msg_reqid = reqid; + p->sadb_msg_reserved2 = reserved2; + + return(buf + len); } /* - * copy sadb type buffer into sadb_ext. - * assume that sadb_ext_len shifted down >> 3. + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. */ static caddr_t -key_copysadbext(p, ext) +key_setsadbsa(buf, sav) + caddr_t buf; + struct secasvar *sav; +{ + struct sadb_sa *p; + u_int len; + + p = (struct sadb_sa *)buf; + len = sizeof(struct sadb_sa); + + bzero(p, len); + p->sadb_sa_len = PFKEY_UNIT64(len); + p->sadb_sa_exttype = SADB_EXT_SA; + p->sadb_sa_spi = sav->spi; + p->sadb_sa_replay = (sav->replay != NULL ? sav->replay->wsize : 0); + p->sadb_sa_state = sav->state; + p->sadb_sa_auth = sav->alg_auth; + p->sadb_sa_encrypt = sav->alg_enc; + p->sadb_sa_flags = sav->flags; + + return(buf + len); +} + +#if 1 +static int +key_setsadbaddr_m(m, exttype, saddr, prefixlen, ul_proto) + struct mbuf *m; + u_int16_t exttype; + struct sockaddr *saddr; + u_int8_t prefixlen; + u_int16_t ul_proto; +{ + caddr_t p; + const size_t len = + sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); + + p = key_appendmbuf(m, len); + if (p == NULL) + return ENOBUFS; + + if (key_setsadbaddr(p, exttype, saddr, prefixlen, ul_proto)) + return 0; + else + return EINVAL; +} +#endif + +/* + * set data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto) + caddr_t buf; + u_int16_t exttype; + struct sockaddr *saddr; + u_int8_t prefixlen; + u_int16_t ul_proto; +{ + struct sadb_address *p; + size_t len; + + p = (struct sadb_address *)buf; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); + + bzero(p, len); + p->sadb_address_len = PFKEY_UNIT64(len); + p->sadb_address_exttype = exttype; + p->sadb_address_proto = ul_proto; + p->sadb_address_prefixlen = prefixlen; + p->sadb_address_reserved = 0; + + bcopy(saddr, p + 1, saddr->sa_len); + + return(buf + len); +} + +/* + * set data into sadb_ident. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbident(buf, exttype, idtype, string, stringlen, id) + caddr_t buf; + u_int16_t exttype, idtype; + caddr_t string; + int stringlen; + u_int64_t id; +{ + struct sadb_ident *p; + u_int len; + + p = (struct sadb_ident *)buf; + len = sizeof(struct sadb_ident) + PFKEY_ALIGN8(stringlen); + + bzero(p, len); + p->sadb_ident_len = PFKEY_UNIT64(len); + p->sadb_ident_exttype = exttype; + p->sadb_ident_type = idtype; + p->sadb_ident_reserved = 0; + p->sadb_ident_id = id; + + bcopy(string, p + 1, stringlen); + + return(buf + len); +} + +/* + * copy buffer of any sadb extension type into sadb_ext. + * assume that sadb_ext_len shifted down >> 3. + * i.e. shift length up when setting length of extension. + */ +static caddr_t +key_setsadbext(p, ext) caddr_t p, ext; { - u_int len = PFKEY_UNUNIT64(((struct sadb_ext *)ext)->sadb_ext_len); + u_int len; + + len = PFKEY_UNUNIT64(((struct sadb_ext *)ext)->sadb_ext_len); bcopy(ext, p, len); return(p + len); } -/* - * `buf' must has been allocated sufficiently. - */ -static caddr_t -key_setsadbaddr(buf, type, family, addr, pref, proto, port) - caddr_t buf, addr; - u_int type, family, pref, proto, port; -{ - caddr_t p = buf; /* save */ - u_int len; - - len = sizeof(struct sadb_address) + PFKEY_ALIGN8(_SALENBYAF(family)); - bzero(p, len); - - ((struct sadb_address *)p)->sadb_address_len = PFKEY_UNIT64(len); - ((struct sadb_address *)p)->sadb_address_exttype = type; - ((struct sadb_address *)p)->sadb_address_proto = proto; - ((struct sadb_address *)p)->sadb_address_prefixlen = pref; - ((struct sadb_address *)p)->sadb_address_reserved = 0; - p += sizeof(struct sadb_address); - - ((struct sockaddr *)p)->sa_len = _SALENBYAF(family); - ((struct sockaddr *)p)->sa_family = family; - _INPORTBYSA(p) = port; - bcopy(addr, _INADDRBYSA(p), _INALENBYAF(family)); - -#ifdef INET6 - /* XXX flowinfo ? scope_id ? */ -#endif /* INET6 */ - - return(buf + len); -} - /* %%% utilities */ /* * copy a buffer into the new buffer allocated. @@ -3135,7 +2924,9 @@ key_newbuf(src, len) KMALLOC(new, caddr_t, len); if (new == NULL) { +#ifdef IPSEC_DEBUG printf("key_newbuf: No more memory.\n"); +#endif return NULL; } bcopy((caddr_t)src, new, len); @@ -3143,258 +2934,6 @@ key_newbuf(src, len) return new; } -/* - * insert keynode after the node pointed as `place' in the keytree. - * If the value of `place' is NULL, key_insnode adds node to the head of tree. - */ -static void -key_insnode(tree, place, node) - void *tree, *place, *node; -{ - register struct keytree *t = (struct keytree *)tree; - register struct keynode *p = (struct keynode *)place; - register struct keynode *n = (struct keynode *)node; - - /* sanity check */ - if (t == NULL || n == NULL) - panic("key_insnode: NULL pointer is passed.\n"); - - KEYDEBUG(KEYDEBUG_KEY_DATA, - printf("begin insnode: %p " - "into %p[len:%d head:%p tail:%p]\n", - n, t, t->len, t->head, t->tail)); - - /* add key into the table */ - if (p == NULL) { -#if 1 /* into head */ - n->next = t->head; - n->prev = (struct keynode *)NULL; - - if (t->head == NULL) - t->tail = n; /* Must be first one. */ - else - t->head->prev = n; - - t->head = n; -#else /* into tail */ - n->next = (struct keynode *)NULL; - n->prev = t->tail; - n->prev->next = n; - - if (t->tail == NULL) - t->head = n; /* Must be first one. */ - else - t->tail->next = n; - - t->tail = n; -#endif - } else { - /* insert key after the place */ - n->next = p->next; - n->next->prev = n; - n->prev = p; - n->prev->next = n; - } - - n->back = (struct keytree *)t; - t->len++; - - KEYDEBUG(KEYDEBUG_KEY_DATA, - printf("end insnode: %p[prev:%p next:%p] " - "into %p[len:%d head:%p tail:%p]\n", - n, n->prev, n->next, t, t->len, t->head, t->tail)); - - return; -} - -/* - * free keynode from keytree. - */ -static void -key_remnode(node) - void *node; -{ - register struct keynode *n = (struct keynode *)node; - - /* sanity check */ - if (n == NULL || n->back == NULL) - panic("key_remnode: NULL pointer is passed.\n"); - - KEYDEBUG(KEYDEBUG_KEY_DATA, - printf("begin remnode: %p " - "from %p[len:%d head:%p tail:%p]\n", - n, n->back, n->back->len, n->back->head, n->back->tail)); - - /* middle */ - if (n->prev && n->next) { - n->prev->next = n->next; - n->next->prev = n->prev; - } else - /* tail */ - if (n->prev && n->next == NULL) { - n->prev->next = NULL; - n->back->tail = n->prev; - } else - /* head */ - if (n->prev == NULL && n->next) { - n->next->prev = NULL; - n->back->head = n->next; - } else { - /* maybe last one */ - /* sn->next == NULL && sn->prev == NULL */ - - /* sanity check */ - if (n->back == NULL) { - printf("key_remnode: Illegal pointer found."); - return; - } - - n->back->head = NULL; - n->back->tail = NULL; - } - - if (n->back) - n->back->len--; - - KEYDEBUG(KEYDEBUG_KEY_DATA, - printf("end remnode: %p " - "from %p[len:%d head:%p tail:%p]\n", - n, n->back, n->back->len, n->back->head, n->back->tail)); - - return; -} - -#ifdef RESTRICTED_DIR -/* - * The relation between the direction of SA and the addresses. - * - * "my address" means my interface's address. - * "my subnet" means my network address. - * "other" means the another of the above. - * - * SA Source SA Destination Proxy Direction Comment - * ------ ----------- ----- --------- ------- - * my address my address bi-direction i.e. loopback - * my address my address my address bi-direction i.e. loopback - * my address my address other N/A - * my address my subnet bi-direction or outbound ? - * my address my subnet my address bi-direction or outbound ? - * my address my subnet other N/A The other way ? - * my address other outbound - * my address other my address N/A - * my address other other outbound - * my subnet my address inbound - * my subnet my address my address inbound or bi-direction - * my subnet my address other N/A - * my subnet my subnet bi-direction - * my subnet my subnet my address N/A bi-direciton ? - * my subnet my subnet other N/A The other way ? - * my subnet other outbound - * my subnet other my address N/A - * my subnet other other outbound - * other my address inbound - * other my address my address inbound - * other my address other N/A - * other my subnet inbound - * other my subnet my address inbound - * other my subnet other N/A The other way ? - * other other N/A SGW Trans. mode - * other other my address inbound - * other other other outbound - */ -static u_int _sec_dirtype[4][4][4] = { -{ -{SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -}, -{ -{SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_BIDIRECT,SADB_X_DIR_BIDIRECT,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_BIDIRECT,SADB_X_DIR_BIDIRECT,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_OUTBOUND,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_OUTBOUND}, -}, -{ -{SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_INBOUND,SADB_X_DIR_INBOUND,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_BIDIRECT,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_OUTBOUND,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_OUTBOUND}, -}, -{ -{SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_INBOUND,SADB_X_DIR_INBOUND,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_INBOUND,SADB_X_DIR_INBOUND,SADB_X_DIR_INVALID,SADB_X_DIR_INVALID}, -{SADB_X_DIR_OUTBOUND,SADB_X_DIR_INBOUND,SADB_X_DIR_INVALID,SADB_X_DIR_OUTBOUND}, -}, -}; - -#define ADDRTYPE_NONE 0 -#define ADDRTYPE_MYADDRESS 1 -#define ADDRTYPE_MYSUBNET 2 -#define ADDRTYPE_OTHER 3 - -/* - * get address type. - * OUT: - * ADDRTYPE_NONE - * ADDRTYPE_MYADDRESS - * ADDRTYPE_MYSUBNET - * ADDRTYPE_OTHER - */ -static u_int -key_getaddrtype(family, addr, preflen) - u_int family, preflen; - caddr_t addr; -{ - if (addr == NULL) - return ADDRTYPE_NONE; - - if (key_ismyaddr(family, addr)) - return ADDRTYPE_MYADDRESS; - else if (key_ismysubnet(family, addr, preflen)) - return ADDRTYPE_MYSUBNET; - - return ADDRTYPE_OTHER; -} - -/* - * check SA's direction. - */ -static u_int -key_checkdir(idx, proxy) - struct secindex *idx; - struct sockaddr *proxy; -{ - u_int srctype, dsttype, proxytype; - /* sanity check */ - if (idx == NULL) - panic("key_checkdir: NULL pointer is passed.\n"); - - /* get src address type */ - srctype = key_getaddrtype(idx->family, (caddr_t)&idx->src, idx->prefs); - KEYDEBUG(KEYDEBUG_KEY_DATA, - printf("key_checkdir: srctype = %d\n", srctype)); - - /* get dst address type */ - dsttype = key_getaddrtype(idx->family, (caddr_t)&idx->dst, idx->prefd); - KEYDEBUG(KEYDEBUG_KEY_DATA, - printf("key_checkdir: dsttype = %d\n", dsttype)); - - /* get proxy address type */ - if (proxy != NULL) { - proxytype = key_getaddrtype(proxy->sa_family, - _INADDRBYSA(proxy), - _INALENBYAF(proxy->sa_family) << 3); - } else - proxytype = ADDRTYPE_NONE; - KEYDEBUG(KEYDEBUG_KEY_DATA, - printf("key_checkdir: proxytype = %d\n", proxytype)); - - return _sec_dirtype[srctype][dsttype][proxytype]; -} -#endif /*RESTRICTED_DIR*/ - /* compare my own address * OUT: 1: true, i.e. my address. * 0: false @@ -3413,14 +2952,7 @@ key_ismyaddr(family, addr) { struct in_ifaddr *ia; -#ifdef __NetBSD__ for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) -#elif defined(__FreeBSD__) && __FreeBSD__ >= 3 - for (ia = in_ifaddrhead.tqh_first; ia; - ia = ia->ia_link.tqe_next) -#else - for (ia = in_ifaddr; ia; ia = ia->ia_next) -#endif if (bcmp(addr, (caddr_t)&ia->ia_addr.sin_addr, _INALENBYAF(family)) == 0) @@ -3463,15 +2995,11 @@ key_ismyaddr6(addr) { struct in6_multi *in6m = 0; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - IN6_LOOKUP_MULTI(*(struct in6_addr *)addr, ia->ia_ifp, in6m); -#else for ((in6m) = ia->ia6_multiaddrs.lh_first; (in6m) != NULL && !IN6_ARE_ADDR_EQUAL(&(in6m)->in6m_addr, a); (in6m) = in6m->in6m_entry.le_next) continue; -#endif if (in6m) return 1; } @@ -3496,56 +3024,7 @@ key_ismyaddr6(addr) } #endif /*INET6*/ -#ifdef RESTRICTED_DIR -/* compare my subnet address - * OUT: 1: true, i.e. my address. - * 0: false - */ -static int -key_ismysubnet(family, addr, preflen) - u_int family, preflen; - caddr_t addr; -{ - /* sanity check */ - if (addr == NULL) - panic("key_ismysubnet: NULL pointer is passed.\n"); - - switch (family) { - case AF_INET: - { - struct in_ifaddr *ia; - -#ifdef __NetBSD__ - for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) -#elif defined(__FreeBSD__) && __FreeBSD__ >= 3 - for (ia = in_ifaddrhead.tqh_first; ia; - ia = ia->ia_link.tqe_next) -#else - for (ia = in_ifaddr; ia; ia = ia->ia_next) -#endif - if (key_bbcmp(addr, - (caddr_t)&ia->ia_addr.sin_addr, - preflen)) - return 1; - } - break; -#ifdef INET6 - case AF_INET6: - { - struct in6_ifaddr *ia; - - for (ia = in6_ifaddr; ia; ia = ia->ia_next) - if (key_bbcmp(addr, - (caddr_t)&ia->ia_addr.sin6_addr, - preflen)) - return 1; - } - break; -#endif - } - return 0; -} - +#if 0 /* checking address is whether loopback or not. * OUT: 1: true * 0: false @@ -3567,47 +3046,91 @@ key_isloopback(family, addr) break; #endif /* INET6 */ default: +#ifdef IPSEC_DEBUG printf("key_isloopback: unknown address family=%d.\n", family); +#endif return 0; } return 0; } -#endif /*RESTRICTED_DIR*/ +#endif /* - * compare two secindex structure. + * compare two secasindex structure exactly. * IN: - * idx0: source - * idx1: object + * saidx0: source, it can be in SAD. + * saidx1: object. * OUT: * 1 : equal * 0 : not equal */ static int -key_cmpidx(idx0, idx1) - struct secindex *idx0, *idx1; +key_cmpsaidx_exactly(saidx0, saidx1) + struct secasindex *saidx0, *saidx1; { /* sanity */ - if (idx0 == NULL && idx1 == NULL) + if (saidx0 == NULL && saidx1 == NULL) return 1; - if (idx0 == NULL || idx1 == NULL) + if (saidx0 == NULL || saidx1 == NULL) return 0; - if (idx0->family != idx1->family - || idx0->prefs != idx1->prefs - || idx0->prefd != idx1->prefd - || idx0->proto != idx1->proto - || idx0->ports != idx1->ports - || idx0->portd != idx1->portd) + if (saidx0->proto != saidx1->proto + || saidx0->mode != saidx1->mode + || saidx0->reqid != saidx1->reqid) + return 0; + + if (bcmp(&saidx0->src, &saidx1->src, saidx0->src.ss_len) != 0 + || bcmp(&saidx0->dst, &saidx1->dst, saidx0->dst.ss_len) != 0) + return 0; + + return 1; +} + +/* + * compare two secasindex structure with consideration mode. + * don't compare port. + * IN: + * saidx0: source, it is often in SAD. + * saidx1: object, it is often from SPD. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpsaidx_withmode(saidx0, saidx1) + struct secasindex *saidx0, *saidx1; +{ + /* sanity */ + if (saidx0 == NULL && saidx1 == NULL) + return 1; + + if (saidx0 == NULL || saidx1 == NULL) + return 0; + + if (saidx0->proto != saidx1->proto + || saidx0->src.ss_family != saidx1->src.ss_family + || saidx0->dst.ss_family != saidx1->dst.ss_family) + return 0; + + /* + * If reqid of SPD is non-zero, unique SA is required. + * The result must be of same reqid in this case. + */ + if (saidx1->reqid != 0 + && saidx0->reqid != saidx1->reqid) + return 0; + + if (saidx0->mode != IPSEC_MODE_ANY + && saidx0->mode != saidx1->mode) return 0; { - int sa_len = _INALENBYAF(idx0->family);; + int sa_len = _INALENBYAF(saidx0->src.ss_family); - if (bcmp((caddr_t)&idx0->src, (caddr_t)&idx1->src, sa_len) != 0 - || bcmp((caddr_t)&idx0->dst, (caddr_t)&idx1->dst, sa_len) != 0) + if (bcmp(_INADDRBYSA(&saidx0->src), _INADDRBYSA(&saidx1->src), sa_len) + || bcmp(_INADDRBYSA(&saidx0->dst), _INADDRBYSA(&saidx1->dst), sa_len)) return 0; } @@ -3615,40 +3138,86 @@ key_cmpidx(idx0, idx1) } /* - * compare two secindex structure with mask. + * compare two secindex structure exactly. * IN: - * idx0: source - * idx1: object + * spidx0: source, it is often in SPD. + * spidx1: object, it is often from PFKEY message. * OUT: * 1 : equal * 0 : not equal */ static int -key_cmpidxwithmask(idx0, idx1) - struct secindex *idx0, *idx1; +key_cmpspidx_exactly(spidx0, spidx1) + struct secpolicyindex *spidx0, *spidx1; { /* sanity */ - if (idx0 == NULL && idx1 == NULL) + if (spidx0 == NULL && spidx1 == NULL) return 1; - if (idx0 == NULL || idx1 == NULL) + if (spidx0 == NULL || spidx1 == NULL) return 0; - if (idx0->family != idx1->family) + if (spidx0->prefs != spidx1->prefs + || spidx0->prefd != spidx1->prefd + || spidx0->ul_proto != spidx1->ul_proto) return 0; - /* XXXif the value in IDX is 0, then the value specified must ignore. */ - if ((idx0->proto != 0 && (idx0->proto != idx1->proto)) - || (idx0->ports != 0 && (idx0->ports != idx1->ports)) - || (idx0->portd != 0 && (idx0->portd != idx1->portd))) + if (bcmp(&spidx0->src, &spidx1->src, spidx0->src.ss_len) != 0 + || bcmp(&spidx0->dst, &spidx1->dst, spidx0->dst.ss_len) != 0) return 0; - if (!key_bbcmp((caddr_t)&idx0->src, (caddr_t)&idx1->src, idx0->prefs)) + return 1; +} + +/* + * compare two secindex structure with mask. + * IN: + * spidx0: source, it is often in SPD. + * spidx1: object, it is often from IP header. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpspidx_withmask(spidx0, spidx1) + struct secpolicyindex *spidx0, *spidx1; +{ + /* sanity */ + if (spidx0 == NULL && spidx1 == NULL) + return 1; + + if (spidx0 == NULL || spidx1 == NULL) return 0; - if (!key_bbcmp((caddr_t)&idx0->dst, (caddr_t)&idx1->dst, idx0->prefd)) + if (spidx0->src.ss_family != spidx1->src.ss_family + || spidx0->dst.ss_family != spidx1->dst.ss_family) return 0; + /* if spidx.ul_proto == IPSEC_ULPROTO_ANY, ignore. */ + if (spidx0->ul_proto != (u_int16_t)IPSEC_ULPROTO_ANY + && spidx0->ul_proto != spidx1->ul_proto) + return 0; + + if (_INPORTBYSA(&spidx0->src) != IPSEC_PORT_ANY + && _INPORTBYSA(&spidx0->src) != _INPORTBYSA(&spidx1->src)) + return 0; + + if (_INPORTBYSA(&spidx0->dst) != IPSEC_PORT_ANY + && _INPORTBYSA(&spidx0->dst) != _INPORTBYSA(&spidx1->dst)) + return 0; + + if (!key_bbcmp(_INADDRBYSA(&spidx0->src), + _INADDRBYSA(&spidx1->src), + spidx0->prefs)) + return 0; + + if (!key_bbcmp(_INADDRBYSA(&spidx0->dst), + _INADDRBYSA(&spidx1->dst), + spidx0->prefd)) + return 0; + + /* XXX Do we check other field ? e.g. flowinfo, scope_id. */ + return 1; } @@ -3692,246 +3261,62 @@ key_bbcmp(p1, p2, bits) /* * time handler. - * scanning SPDB and SADB to check status for each entries, + * scanning SPD and SAD to check status for each entries, * and do to remove or to expire. */ void key_timehandler(void) { -#ifdef RESTRICTED_DIR - u_int diridx, dir; -#endif + u_int dir; int s; -#ifdef __NetBSD__ s = splsoftnet(); /*called from softclock()*/ -#else - s = splnet(); /*called from softclock()*/ -#endif /* SPD */ { - struct secpolicy *sp, *spnext; + struct secpolicy *sp, *nextsp; -#ifdef RESTRICTED_DIR - for (diridx = 0; diridx < _ARRAYLEN(saorder_dir_any); diridx++) { - - dir = saorder_dir_any[diridx]; - for (sp = (struct secpolicy *)sptree[dir].head; + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + for (sp = LIST_FIRST(&sptree[dir]); sp != NULL; - sp = spnext) { + sp = nextsp) { - spnext = sp->next; + nextsp = LIST_NEXT(sp, chain); if (sp->state == IPSEC_SPSTATE_DEAD) key_freesp(sp); } } -#else - for (sp = (struct secpolicy *)sptree.head; - sp != NULL; - sp = spnext) { - - spnext = sp->next; - - if (sp->state == IPSEC_SPSTATE_DEAD) - key_freesp(sp); - } -#endif } /* SAD */ { - struct secasindex *saidx, *saidxnext; - struct secas *sa, *sanext; + struct secashead *sah, *nextsah; + struct secasvar *sav, *nextsav; -#ifdef RESTRICTED_DIR - for (diridx = 0; diridx < _ARRAYLEN(saorder_dir_any); diridx++) { + for (sah = LIST_FIRST(&sahtree); + sah != NULL; + sah = nextsah) { - dir = saorder_dir_any[diridx]; - for (saidx = (struct secasindex *)saidxtree[dir].head; - saidx != NULL; - saidx = saidxnext) { + nextsah = LIST_NEXT(sah, chain); - saidxnext = saidx->next; /* save for removing */ - - /* if LARVAL entry doesn't become MATURE, delete it. */ - for (sa = (struct secas *)saidx->satree[SADB_SASTATE_LARVAL].head; - sa != NULL; - sa = sanext) { - - sanext = sa->next; /* save */ - - sa->tick++; - - if (key_larval_lifetime < sa->tick) { - key_freesa(sa); - } - } - - /* - * check MATURE entry to start to send expire message - * whether or not. - */ - for (sa = (struct secas *)saidx->satree[SADB_SASTATE_MATURE].head; - sa != NULL; - sa = sanext) { - - sanext = sa->next; /* save */ - - sa->tick++; - - /* we don't need to check. */ - if (sa->lft_s == NULL) - continue; - - /* sanity check */ - if (sa->lft_c == NULL) { - printf("key_timehandler: " - "There is no the CURRENT, " - "why?\n"); - continue; - } - - /* compare SOFT lifetime and tick */ - if (sa->lft_s->sadb_lifetime_addtime != 0 - && sa->lft_s->sadb_lifetime_addtime < sa->tick) { - /* - * check SA to be used whether or not. - * when SA hasn't been used, delete it. - */ - if (sa->lft_c->sadb_lifetime_usetime == 0) { - key_sa_chgstate(sa, SADB_SASTATE_DEAD); - key_freesa(sa); - sa = NULL; - } else { - key_sa_chgstate(sa, SADB_SASTATE_DYING); - /* - * XXX If we keep to send expire - * message in the status of - * DYING. Do remove below code. - */ - key_expire(sa); - } - } - /* check SOFT lifetime by bytes */ - /* - * XXX I don't know the way to delete this SA - * when new SA is installed. Caution when it's - * installed too big lifetime by time. - */ - else if (sa->lft_s->sadb_lifetime_bytes != 0 - && sa->lft_s->sadb_lifetime_bytes < sa->lft_c->sadb_lifetime_bytes) { - - key_sa_chgstate(sa, SADB_SASTATE_DYING); - /* - * XXX If we keep to send expire - * message in the status of - * DYING. Do remove below code. - */ - key_expire(sa); - } - } - - /* check DYING entry to change status to DEAD. */ - for (sa = (struct secas *)saidx->satree[SADB_SASTATE_DYING].head; - sa != NULL; - sa = sanext) { - - sanext = sa->next; /* save */ - - sa->tick++; - - /* we don't need to check. */ - if (sa->lft_h == NULL) - continue; - - /* sanity check */ - if (sa->lft_c == NULL) { - printf("key_timehandler: " - "There is no the CURRENT, " - "why?\n"); - continue; - } - - /* compare HARD lifetime and tick */ - if (sa->lft_h->sadb_lifetime_addtime != 0 - && sa->lft_h->sadb_lifetime_addtime < sa->tick) { - key_sa_chgstate(sa, SADB_SASTATE_DEAD); - key_freesa(sa); - sa = NULL; - } -#if 0 /* XXX Should we keep to send expire message until HARD lifetime ? */ - else if (sa->lft_s != NULL - && sa->lft_s->sadb_lifetime_addtime != 0 - && sa->lft_s->sadb_lifetime_addtime < sa->tick) { - /* - * XXX: should be checked to be - * installed the valid SA. - */ - - /* - * If there is no SA then sending - * expire message. - */ - key_expire(sa); - } -#endif - /* check HARD lifetime by bytes */ - else if (sa->lft_h->sadb_lifetime_bytes != 0 - && sa->lft_h->sadb_lifetime_bytes < sa->lft_c->sadb_lifetime_bytes) { - key_sa_chgstate(sa, SADB_SASTATE_DEAD); - key_freesa(sa); - sa = NULL; - } - } - - /* delete entry in DEAD */ - for (sa = (struct secas *)saidx->satree[SADB_SASTATE_DEAD].head; - sa != NULL; - sa = sanext) { - - sanext = sa->next; /* save */ - - /* sanity check */ - if (sa->state != SADB_SASTATE_DEAD) { - printf("key_timehandler: " - "invalid sa->state " - "(queue: %d SA: %d): " - "kill it anyway\n", - SADB_SASTATE_DEAD, sa->state); - } - - /* - * do not call key_freesa() here. - * sa should already be freed, and sa->refcnt - * shows other references to sa - * (such as from SPD). - */ - } - - /* If there is no SA entry in SA index, marking DEAD. */ - key_issaidx_dead(saidx); + /* if sah has been dead, then delete it and process next sah. */ + if (sah->state == SADB_SASTATE_DEAD) { + key_delsah(sah); + continue; } - } -#else - for (saidx = (struct secasindex *)saidxtree.head; - saidx != NULL; - saidx = saidxnext) { - - saidxnext = saidx->next; /* save for removing */ /* if LARVAL entry doesn't become MATURE, delete it. */ - for (sa = (struct secas *)saidx->satree[SADB_SASTATE_LARVAL].head; - sa != NULL; - sa = sanext) { + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_LARVAL]); + sav != NULL; + sav = nextsav) { - sanext = sa->next; /* save */ + nextsav = LIST_NEXT(sav, chain); - sa->tick++; + sav->tick++; - if (key_larval_lifetime < sa->tick) { - key_freesa(sa); + if (key_larval_lifetime < sav->tick) { + key_freesav(sav); } } @@ -3939,45 +3324,46 @@ key_timehandler(void) * check MATURE entry to start to send expire message * whether or not. */ - for (sa = (struct secas *)saidx->satree[SADB_SASTATE_MATURE].head; - sa != NULL; - sa = sanext) { + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_MATURE]); + sav != NULL; + sav = nextsav) { - sanext = sa->next; /* save */ + nextsav = LIST_NEXT(sav, chain); - sa->tick++; + sav->tick++; /* we don't need to check. */ - if (sa->lft_s == NULL) + if (sav->lft_s == NULL) continue; /* sanity check */ - if (sa->lft_c == NULL) { + if (sav->lft_c == NULL) { +#ifdef IPSEC_DEBUG printf("key_timehandler: " - "There is no the CURRENT, " - "why?\n"); + "There is no CURRENT time, why?\n"); +#endif continue; } /* compare SOFT lifetime and tick */ - if (sa->lft_s->sadb_lifetime_addtime != 0 - && sa->lft_s->sadb_lifetime_addtime < sa->tick) { + if (sav->lft_s->sadb_lifetime_addtime != 0 + && sav->lft_s->sadb_lifetime_addtime < sav->tick) { /* * check SA to be used whether or not. * when SA hasn't been used, delete it. */ - if (sa->lft_c->sadb_lifetime_usetime == 0) { - key_sa_chgstate(sa, SADB_SASTATE_DEAD); - key_freesa(sa); - sa = NULL; + if (sav->lft_c->sadb_lifetime_usetime == 0) { + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; } else { - key_sa_chgstate(sa, SADB_SASTATE_DYING); + key_sa_chgstate(sav, SADB_SASTATE_DYING); /* * XXX If we keep to send expire * message in the status of * DYING. Do remove below code. */ - key_expire(sa); + key_expire(sav); } } /* check SOFT lifetime by bytes */ @@ -3986,51 +3372,52 @@ key_timehandler(void) * when new SA is installed. Caution when it's * installed too big lifetime by time. */ - else if (sa->lft_s->sadb_lifetime_bytes != 0 - && sa->lft_s->sadb_lifetime_bytes < sa->lft_c->sadb_lifetime_bytes) { + else if (sav->lft_s->sadb_lifetime_bytes != 0 + && sav->lft_s->sadb_lifetime_bytes < sav->lft_c->sadb_lifetime_bytes) { - key_sa_chgstate(sa, SADB_SASTATE_DYING); + key_sa_chgstate(sav, SADB_SASTATE_DYING); /* * XXX If we keep to send expire * message in the status of * DYING. Do remove below code. */ - key_expire(sa); + key_expire(sav); } } /* check DYING entry to change status to DEAD. */ - for (sa = (struct secas *)saidx->satree[SADB_SASTATE_DYING].head; - sa != NULL; - sa = sanext) { + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_DYING]); + sav != NULL; + sav = nextsav) { - sanext = sa->next; /* save */ + nextsav = LIST_NEXT(sav, chain); - sa->tick++; + sav->tick++; /* we don't need to check. */ - if (sa->lft_h == NULL) + if (sav->lft_h == NULL) continue; /* sanity check */ - if (sa->lft_c == NULL) { + if (sav->lft_c == NULL) { +#ifdef IPSEC_DEBUG printf("key_timehandler: " - "There is no the CURRENT, " - "why?\n"); + "There is no CURRENT time, why?\n"); +#endif continue; } /* compare HARD lifetime and tick */ - if (sa->lft_h->sadb_lifetime_addtime != 0 - && sa->lft_h->sadb_lifetime_addtime < sa->tick) { - key_sa_chgstate(sa, SADB_SASTATE_DEAD); - key_freesa(sa); - sa = NULL; + if (sav->lft_h->sadb_lifetime_addtime != 0 + && sav->lft_h->sadb_lifetime_addtime < sav->tick) { + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; } #if 0 /* XXX Should we keep to send expire message until HARD lifetime ? */ - else if (sa->lft_s != NULL - && sa->lft_s->sadb_lifetime_addtime != 0 - && sa->lft_s->sadb_lifetime_addtime < sa->tick) { + else if (sav->lft_s != NULL + && sav->lft_s->sadb_lifetime_addtime != 0 + && sav->lft_s->sadb_lifetime_addtime < sav->tick) { /* * XXX: should be checked to be * installed the valid SA. @@ -4040,63 +3427,62 @@ key_timehandler(void) * If there is no SA then sending * expire message. */ - key_expire(sa); + key_expire(sav); } #endif /* check HARD lifetime by bytes */ - else if (sa->lft_h->sadb_lifetime_bytes != 0 - && sa->lft_h->sadb_lifetime_bytes < sa->lft_c->sadb_lifetime_bytes) { - key_sa_chgstate(sa, SADB_SASTATE_DEAD); - key_freesa(sa); - sa = NULL; + else if (sav->lft_h->sadb_lifetime_bytes != 0 + && sav->lft_h->sadb_lifetime_bytes < sav->lft_c->sadb_lifetime_bytes) { + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; } } /* delete entry in DEAD */ - for (sa = (struct secas *)saidx->satree[SADB_SASTATE_DEAD].head; - sa != NULL; - sa = sanext) { + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_DEAD]); + sav != NULL; + sav = nextsav) { - sanext = sa->next; /* save */ + nextsav = LIST_NEXT(sav, chain); /* sanity check */ - if (sa->state != SADB_SASTATE_DEAD) { + if (sav->state != SADB_SASTATE_DEAD) { +#ifdef IPSEC_DEBUG printf("key_timehandler: " - "invalid sa->state " + "invalid sav->state " "(queue: %d SA: %d): " "kill it anyway\n", - SADB_SASTATE_DEAD, sa->state); + SADB_SASTATE_DEAD, sav->state); +#endif } /* - * do not call key_freesa() here. - * sa should already be freed, and sa->refcnt - * shows other references to sa + * do not call key_freesav() here. + * sav should already be freed, and sav->refcnt + * shows other references to sav * (such as from SPD). */ } - - /* If there is no SA entry in SA index, marking DEAD. */ - key_issaidx_dead(saidx); } -#endif } #ifndef IPSEC_NONBLOCK_ACQUIRE /* ACQ tree */ { - struct secacq *acq, *acqnext; + struct secacq *acq, *nextacq; - for (acq = (struct secacq *)acqtree.head; + for (acq = LIST_FIRST(&acqtree); acq != NULL; - acq = acqnext) { + acq = nextacq) { - acqnext = acq->next; + nextacq = LIST_NEXT(acq, chain); acq->tick++; - if (key_blockacq_lifetime < acq->tick) { - key_delacq(acq); + if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) { + LIST_REMOVE(acq, chain); + KFREE(acq); } } } @@ -4124,22 +3510,66 @@ void key_srandom() { struct timeval tv; -#ifdef __bsdi__ - extern long randseed; /* it's defined at i386/i386/random.s */ -#endif /* __bsdi__ */ microtime(&tv); -#ifdef __FreeBSD__ - srandom(tv.tv_usec); -#endif /* __FreeBSD__ */ -#ifdef __bsdi__ - randseed = tv.tv_usec; -#endif /* __bsdi__ */ return; } +/* + * map SADB_SATYPE_* to IPPROTO_*. + * if satype == SADB_SATYPE then satype is mapped to ~0. + * OUT: + * 0: invalid satype. + */ +static u_int16_t +key_satype2proto(satype) + u_int8_t satype; +{ + switch (satype) { + case SADB_SATYPE_UNSPEC: + return IPSEC_PROTO_ANY; + case SADB_SATYPE_AH: + return IPPROTO_AH; + case SADB_SATYPE_ESP: + return IPPROTO_ESP; +#if 1 /*nonstandard*/ + case SADB_X_SATYPE_IPCOMP: + return IPPROTO_IPCOMP; + break; +#endif + default: + return 0; + } + /* NOTREACHED */ +} + +/* + * map IPPROTO_* to SADB_SATYPE_* + * OUT: + * 0: invalid protocol type. + */ +static u_int8_t +key_proto2satype(proto) + u_int16_t proto; +{ + switch (proto) { + case IPPROTO_AH: + return SADB_SATYPE_AH; + case IPPROTO_ESP: + return SADB_SATYPE_ESP; +#if 1 /*nonstandard*/ + case IPPROTO_IPCOMP: + return SADB_X_SATYPE_IPCOMP; + break; +#endif + default: + return 0; + } + /* NOTREACHED */ +} + /* %%% PF_KEY */ /* * SADB_GETSPI processing is to receive @@ -4159,12 +3589,10 @@ key_getspi(mhp) { struct sadb_msg *msg0; struct sadb_address *src0, *dst0; - struct secindex idx; - struct secasindex *newsaidx; - struct secas *newsa; -#ifdef RESTRICTED_DIR - u_int dir; -#endif + struct secasindex saidx; + struct secashead *newsah; + struct secasvar *newsav; + u_int8_t proto; u_int32_t spi; /* sanity check */ @@ -4175,7 +3603,9 @@ key_getspi(mhp) if (mhp[SADB_EXT_ADDRESS_SRC] == NULL || mhp[SADB_EXT_ADDRESS_DST] == NULL) { +#ifdef IPSEC_DEBUG printf("key_getspi: invalid message is passed.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; } @@ -4183,92 +3613,52 @@ key_getspi(mhp) src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - /* make secindex */ - if (key_setsecidx(src0, dst0, &idx, 0)) { + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { +#ifdef IPSEC_DEBUG + printf("key_getspi: invalid satype is passed.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; } -#ifdef RESTRICTED_DIR - /* check the direciton. */ - /* - * We call key_checkdir with both the source address and - * the destination address, but the proxy address is *ZERO*. - * Even if Proxy address is set by SADB_UPDATE later, the SA direction - * is not changed or is changed into invalid status. - * When both the src and dst address are `other' and the proxy address - * is null, key_checkdir() returns SADB_X_DIR_INVALID. We take this - * SA as SADB_X_DIR_INBOUND. Because it will become inbound SA when - * proxy address is set `my address'. If the proxy address is set - * either `none' or `other', it is invalid SA. - */ - dir = key_checkdir(&idx, NULL); - switch (dir) { - case SADB_X_DIR_INVALID: - dir = SADB_X_DIR_INBOUND; - /*FALLTHROUGH*/ - case SADB_X_DIR_INBOUND: - case SADB_X_DIR_BIDIRECT: - break; - case SADB_X_DIR_OUTBOUND: - printf("key_getspi: Invalid SA direction.\n"); - msg0->sadb_msg_errno = EINVAL; - return NULL; - default: - panic("key_getspi: unexpected direction.\n"); - } -#endif + KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); /* SPI allocation */ spi = key_do_getnewspi((struct sadb_spirange *)mhp[SADB_EXT_SPIRANGE], - msg0->sadb_msg_satype); + &saidx); if (spi == 0) { msg0->sadb_msg_errno = EEXIST; return NULL; } /* get a SA index */ -#ifdef RESTRICTED_DIR - if ((newsaidx = key_getsaidx(&idx, dir)) == NULL) { + if ((newsah = key_getsah(&saidx)) == NULL) { /* create a new SA index */ - if ((newsaidx = key_newsaidx(&idx, dir)) == NULL) { + if ((newsah = key_newsah(&saidx)) == NULL) { +#ifdef IPSEC_DEBUG printf("key_getspi: No more memory.\n"); - msg0->sadb_msg_errno = ENOBUFS; - return NULL; - } - } -#else - if ((newsaidx = key_getsaidx(&idx)) == NULL) { - - /* create a new SA index */ - if ((newsaidx = key_newsaidx(&idx)) == NULL) { - printf("key_getspi: No more memory.\n"); - msg0->sadb_msg_errno = ENOBUFS; - return NULL; - } - } #endif + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + } /* get a new SA */ - if ((newsa = key_newsa(mhp, newsaidx)) == NULL) { + if ((newsav = key_newsav(mhp, newsah)) == NULL) { msg0->sadb_msg_errno = ENOBUFS; /* XXX don't free new SA index allocated in above. */ return NULL; } /* set spi */ - newsa->spi = htonl(spi); + newsav->spi = htonl(spi); #ifndef IPSEC_NONBLOCK_ACQUIRE /* delete the entry in acqtree */ if (msg0->sadb_msg_seq != 0) { struct secacq *acq; - /* - * it's only sequence number to connect - * the entry for getspi and the entry in acqtree - * because there is not proxy address in getspi message. - */ if ((acq = key_getacqbyseq(msg0->sadb_msg_seq)) != NULL) { /* reset counter in order to deletion by timehander. */ acq->tick = key_blockacq_lifetime; @@ -4290,14 +3680,16 @@ key_getspi(mhp) KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) { +#ifdef IPSEC_DEBUG printf("key_getspi: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } bzero((caddr_t)newmsg, len); bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); - newmsg->sadb_msg_seq = newsa->seq; + newmsg->sadb_msg_seq = newsav->seq; newmsg->sadb_msg_errno = 0; newmsg->sadb_msg_len = PFKEY_UNIT64(len); p = (caddr_t)newmsg + sizeof(*msg0); @@ -4311,8 +3703,8 @@ key_getspi(mhp) p += sizeof(struct sadb_sa); } - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); return newmsg; } @@ -4326,9 +3718,9 @@ key_getspi(mhp) * others: success. */ static u_int32_t -key_do_getnewspi(spirange, satype) +key_do_getnewspi(spirange, saidx) struct sadb_spirange *spirange; - u_int satype; + struct secasindex *saidx; { u_int32_t newspi; u_int32_t min, max; @@ -4343,7 +3735,7 @@ key_do_getnewspi(spirange, satype) max = key_spi_maxval; } /* IPCOMP needs 2-byte SPI */ - if (satype == SADB_X_SATYPE_IPCOMP) { + if (saidx->proto == IPPROTO_IPCOMP) { u_int32_t t; if (min >= 0x10000) min = 0xffff; @@ -4355,8 +3747,10 @@ key_do_getnewspi(spirange, satype) } if (min == max) { - if (key_checkspi(min, satype) != NULL) { + if (key_checkspidup(saidx, min) != NULL) { +#ifdef IPSEC_DEBUG printf("key_do_getnewspi: SPI %u exists already.\n", min); +#endif return 0; } @@ -4373,12 +3767,14 @@ key_do_getnewspi(spirange, satype) /* generate pseudo-random SPI value ranged. */ newspi = min + (random() % ( max - min + 1 )); - if (key_checkspi(newspi, satype) == NULL) + if (key_checkspidup(saidx, newspi) == NULL) break; } if (count == 0 || newspi == 0) { +#ifdef IPSEC_DEBUG printf("key_do_getnewspi: to allocate spi is failed.\n"); +#endif return 0; } } @@ -4395,7 +3791,7 @@ key_do_getnewspi(spirange, satype) * receive * - * from the ikmpd, and update a secas entry whose status is SADB_SASTATE_LARVAL. + * from the ikmpd, and update a secasvar entry whose status is SADB_SASTATE_LARVAL. * and send * @@ -4412,13 +3808,10 @@ key_update(mhp) struct sadb_msg *msg0; struct sadb_sa *sa0; struct sadb_address *src0, *dst0; - struct sockaddr *proxy; - struct secindex idx; - struct secasindex *saidx; - struct secas *sa; -#ifdef RESTRICTED_DIR - u_int dir; -#endif + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; /* sanity check */ if (mhp == NULL || mhp[0] == NULL) @@ -4426,142 +3819,123 @@ key_update(mhp) msg0 = (struct sadb_msg *)mhp[0]; - msg0->sadb_msg_errno = 0; - if (mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { +#ifdef IPSEC_DEBUG + printf("key_update: invalid satype is passed.\n"); +#endif msg0->sadb_msg_errno = EINVAL; + return NULL; } - switch (msg0->sadb_msg_satype) { - case SADB_SATYPE_AH: - if (mhp[SADB_EXT_KEY_AUTH] == NULL) - msg0->sadb_msg_errno = EINVAL; - break; - case SADB_SATYPE_ESP: - if (mhp[SADB_EXT_KEY_ENCRYPT] == NULL) - msg0->sadb_msg_errno = EINVAL; - break; - } - if (msg0->sadb_msg_errno) { + + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || (msg0->sadb_msg_satype == SADB_SATYPE_ESP + && mhp[SADB_EXT_KEY_ENCRYPT] == NULL) + || (msg0->sadb_msg_satype == SADB_SATYPE_AH + && mhp[SADB_EXT_KEY_AUTH] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] != NULL + && mhp[SADB_EXT_LIFETIME_SOFT] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] == NULL + && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { +#ifdef IPSEC_DEBUG printf("key_update: invalid message is passed.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; return NULL; } sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - if (mhp[SADB_EXT_ADDRESS_PROXY] == NULL) - proxy = NULL; - else - proxy = (struct sockaddr *)(mhp[SADB_EXT_ADDRESS_PROXY] - + sizeof(struct sadb_address)); - /* make secindex */ - if (key_setsecidx(src0, dst0, &idx, 0)) { - msg0->sadb_msg_errno = EINVAL; - return NULL; - } + KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); -#ifdef RESTRICTED_DIR - /* - * check the direciton with proxy address. - * We assumed that SA direction is not changed if valid SA. - * See key_getspi(). - */ - dir = key_checkdir(&idx, proxy); - switch (dir) { - case SADB_X_DIR_INBOUND: - case SADB_X_DIR_BIDIRECT: - break; - case SADB_X_DIR_OUTBOUND: - case SADB_X_DIR_INVALID: - printf("key_update: Invalid SA direction.\n"); - msg0->sadb_msg_errno = EINVAL; - return NULL; - default: - panic("key_update: unexpected direction.\n"); - } - -#if 1 /* XXX */ - /* sanity check for direction */ - { - u_int olddir; - - olddir = key_checkdir(&idx, NULL); - if (dir != olddir) { - printf("key_update: mismatched SA direction %u -> %u.\n", - olddir, dir); - msg0->sadb_msg_errno = EINVAL; - return NULL; - } - } -#endif -#endif - - /* get a SA index */ -#ifdef RESTRICTED_DIR - if ((saidx = key_getsaidx(&idx, dir)) == NULL) { + /* get a SA header */ + if ((sah = key_getsah(&saidx)) == NULL) { +#ifdef IPSEC_DEBUG printf("key_update: no SA index found.\n"); +#endif + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + /* set spidx if there */ + if (key_setident(sah, mhp) < 0) + return NULL; + + /* find a SA with sequence number. */ +#ifdef IPSEC_DOSEQCHECK + if (msg0->sadb_msg_seq != 0 + && (sav = key_getsavbyseq(sah, msg0->sadb_msg_seq)) == NULL) { +#ifdef IPSEC_DEBUG + printf("key_update: no larval SA with sequence %u exists.\n", + msg0->sadb_msg_seq); +#endif msg0->sadb_msg_errno = ENOENT; return NULL; } #else - if ((saidx = key_getsaidx(&idx)) == NULL) { - printf("key_update: no SA index found.\n"); - msg0->sadb_msg_errno = ENOENT; + if ((sav = key_getsavbyspi(sah, sa0->sadb_sa_spi)) == NULL) { +#ifdef IPSEC_DEBUG + printf("key_update: no such a SA found (spi:%u)\n", + (u_int32_t)ntohl(sa0->sadb_sa_spi)); +#endif + msg0->sadb_msg_errno = EINVAL; return NULL; } #endif - /* find a SA with sequence number. */ - if ((sa = key_getsabyseq(saidx, msg0->sadb_msg_seq)) == NULL) { - printf("key_update: no larval SA with sequence %u exists.\n", - msg0->sadb_msg_seq); - msg0->sadb_msg_errno = ENOENT; + /* validity check */ + if (sav->sah->saidx.proto != proto) { +#ifdef IPSEC_DEBUG + printf("key_update: protocol mismatched (DB=%u param=%u)\n", + sav->sah->saidx.proto, proto); +#endif + msg0->sadb_msg_errno = EINVAL; + return NULL; + } +#ifdef IPSEC_DOSEQCHECK + if (sav->spi != sa0->sadb_sa_spi) { +#ifdef IPSEC_DEBUG + printf("key_update: SPI mismatched (DB:%u param:%u)\n", + (u_int32_t)ntohl(sav->spi), + (u_int32_t)ntohl(sa0->sadb_sa_spi)); +#endif + msg0->sadb_msg_errno = EINVAL; + return NULL; + } +#endif + if (sav->pid != msg0->sadb_msg_pid) { +#ifdef IPSEC_DEBUG + printf("key_update: pid mismatched (DB:%u param:%u)\n", + sav->pid, msg0->sadb_msg_pid); +#endif + msg0->sadb_msg_errno = EINVAL; return NULL; } - /* validity check */ - /* Are these error ? Now warning. */ - if (sa->type != msg0->sadb_msg_satype) { - printf("key_update: protocol mismatched (DB:%u param:%u)\n", - sa->type, msg0->sadb_msg_satype); - } - if (sa->spi != sa0->sadb_sa_spi) { - printf("key_update: SPI mismatched (DB:%u param:%u)\n", - (u_int32_t)ntohl(sa->spi), - (u_int32_t)ntohl(sa0->sadb_sa_spi)); - } - if (sa->pid != msg0->sadb_msg_pid) { - printf("key_update: pid mismatched (DB:%u param:%u)\n", - sa->pid, msg0->sadb_msg_pid); - } - - /* copy sa values */ - if (key_setsaval(sa, mhp)) { - key_freesa(sa); + /* copy sav values */ + if (key_setsaval(sav, mhp)) { + key_freesav(sav); return NULL; } /* check SA values to be mature. */ - if ((msg0->sadb_msg_errno = key_mature(sa)) != 0) { - key_freesa(sa); + if ((msg0->sadb_msg_errno = key_mature(sav)) != 0) { + key_freesav(sav); return NULL; } - /* - * we must call key_freesa() whenever we leave a function context, - * as we did not allocated a new sa (we updated existing sa). - */ - key_freesa(sa); - sa = NULL; - { struct sadb_msg *newmsg; /* set msg buf from mhp */ if ((newmsg = key_getmsgbuf_x1(mhp)) == NULL) { +#ifdef IPSEC_DEBUG printf("key_update: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } @@ -4570,42 +3944,41 @@ key_update(mhp) } /* - * search SADB with sequence for a SA which state is SADB_SASTATE_LARVAL. + * search SAD with sequence for a SA which state is SADB_SASTATE_LARVAL. * only called by key_update(). * OUT: * NULL : not found * others : found, pointer to a SA. */ -static struct secas * -key_getsabyseq(saidx, seq) - struct secasindex *saidx; +#ifdef IPSEC_DOSEQCHECK +static struct secasvar * +key_getsavbyseq(sah, seq) + struct secashead *sah; u_int32_t seq; { - struct secas *sa; + struct secasvar *sav; u_int state; state = SADB_SASTATE_LARVAL; - /* Is there a SA with sequence number ? */ - for (sa = (struct secas *)saidx->satree[state].head; - sa != NULL; - sa = sa->next) { + /* search SAD with sequence number ? */ + LIST_FOREACH(sav, &sah->savtree[state], chain) { - /* sanity check */ - if (sa->state != state) { - printf("key_getsabyseq: invalid sa->state " - "(DB:%u param:%u)\n", sa->state, state); - continue; - } + KEY_CHKSASTATE(state, sav->state, "key_getsabyseq"); - if (sa->seq == seq) { - sa->refcnt++; - return sa; + if (sav->seq == seq) { + sav->refcnt++; + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP key_getsavbyseq cause " + "refcnt++:%d SA:%p\n", + sav->refcnt, sav)); + return sav; } } return NULL; } +#endif /* * SADB_ADD processing @@ -4631,13 +4004,10 @@ key_add(mhp) struct sadb_msg *msg0; struct sadb_sa *sa0; struct sadb_address *src0, *dst0; - struct sockaddr *proxy; - struct secindex idx; - struct secasindex *newsaidx; - struct secas *newsa; -#ifdef RESTRICTED_DIR - u_int dir; -#endif + struct secasindex saidx; + struct secashead *newsah; + struct secasvar *newsav; + u_int16_t proto; /* sanity check */ if (mhp == NULL || mhp[0] == NULL) @@ -4645,118 +4015,76 @@ key_add(mhp) msg0 = (struct sadb_msg *)mhp[0]; - msg0->sadb_msg_errno = 0; + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { +#ifdef IPSEC_DEBUG + printf("key_add: invalid satype is passed.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + if (mhp[SADB_EXT_SA] == NULL || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { - msg0->sadb_msg_errno = EINVAL; - } - switch (msg0->sadb_msg_satype) { - case SADB_SATYPE_AH: - if (mhp[SADB_EXT_KEY_AUTH] == NULL) - msg0->sadb_msg_errno = EINVAL; - break; - case SADB_SATYPE_ESP: - if (mhp[SADB_EXT_KEY_ENCRYPT] == NULL) - msg0->sadb_msg_errno = EINVAL; - break; - } - if (msg0->sadb_msg_errno) { + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || (msg0->sadb_msg_satype == SADB_SATYPE_ESP + && mhp[SADB_EXT_KEY_ENCRYPT] == NULL) + || (msg0->sadb_msg_satype == SADB_SATYPE_AH + && mhp[SADB_EXT_KEY_AUTH] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] != NULL + && mhp[SADB_EXT_LIFETIME_SOFT] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] == NULL + && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { +#ifdef IPSEC_DEBUG printf("key_add: invalid message is passed.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; return NULL; } sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - if (mhp[SADB_EXT_ADDRESS_PROXY] == NULL) - proxy = NULL; - else - proxy = (struct sockaddr *)(mhp[SADB_EXT_ADDRESS_PROXY] - + sizeof(struct sadb_address)); - /* make secindex */ - if (key_setsecidx(src0, dst0, &idx, 0)) { - msg0->sadb_msg_errno = EINVAL; - return NULL; - } + KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); -#ifdef RESTRICTED_DIR - /* checking the direciton. */ - dir = key_checkdir(&idx, proxy); - switch (dir) { - case SADB_X_DIR_INBOUND: - case SADB_X_DIR_BIDIRECT: /* XXX Is it need for bi-direction ? */ - /* checking SPI duplication. */ - if (key_checkspi(sa0->sadb_sa_spi, msg0->sadb_msg_satype) - != NULL) { - printf("key_add: SPI %u exists already.\n", - (u_int32_t)ntohl(sa0->sadb_sa_spi)); - msg0->sadb_msg_errno = EEXIST; - return NULL; - } - break; - case SADB_X_DIR_OUTBOUND: - /* checking SPI & address duplication. */ - { - struct secasindex *saidx_tmp; - saidx_tmp = key_getsaidx(&idx, dir); - if (saidx_tmp != NULL - && key_getsabyspi(saidx_tmp, - msg0->sadb_msg_satype, - sa0->sadb_sa_spi) != NULL) { - printf("key_add: SA exists already, SPI=%u\n", - (u_int32_t)ntohl(sa0->sadb_sa_spi)); - msg0->sadb_msg_errno = EEXIST; - return NULL; - } - } - break; - case SADB_X_DIR_INVALID: - printf("key_add: Invalid SA direction.\n"); - msg0->sadb_msg_errno = EINVAL; - return NULL; - default: - panic("key_add: unexpected direction %u", dir); - } -#endif + /* get a SA header */ + if ((newsah = key_getsah(&saidx)) == NULL) { - /* get a SA index */ -#ifdef RESTRICTED_DIR - if ((newsaidx = key_getsaidx(&idx, dir)) == NULL) { - - /* create a new SA index */ - if ((newsaidx = key_newsaidx(&idx, dir)) == NULL) { + /* create a new SA header */ + if ((newsah = key_newsah(&saidx)) == NULL) { +#ifdef IPSEC_DEBUG printf("key_add: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } } -#else - if ((newsaidx = key_getsaidx(&idx)) == NULL) { - /* create a new SA index */ - if ((newsaidx = key_newsaidx(&idx)) == NULL) { - printf("key_add: No more memory.\n"); - msg0->sadb_msg_errno = ENOBUFS; - return NULL; - } - } -#endif + /* set spidx if there */ + if (key_setident(newsah, mhp) < 0) + return NULL; /* create new SA entry. */ /* We can create new SA only if SPI is differenct. */ - if ((newsa = key_newsa(mhp, newsaidx)) == NULL) + if (key_getsavbyspi(newsah, sa0->sadb_sa_spi)) { +#ifdef IPSEC_DEBUG + printf("key_add: SA already exists.\n"); +#endif + msg0->sadb_msg_errno = EEXIST; + return NULL; + } + if ((newsav = key_newsav(mhp, newsah)) == NULL) return NULL; /* check SA values to be mature. */ - if ((msg0->sadb_msg_errno = key_mature(newsa)) != NULL) { - key_freesa(newsa); + if ((msg0->sadb_msg_errno = key_mature(newsav)) != NULL) { + key_freesav(newsav); return NULL; } /* - * don't call key_freesa() here, as we would like to keep the SA + * don't call key_freesav() here, as we would like to keep the SA * in the database on success. */ @@ -4765,7 +4093,9 @@ key_add(mhp) /* set msg buf from mhp */ if ((newmsg = key_getmsgbuf_x1(mhp)) == NULL) { - printf("key_update: No more memory.\n"); +#ifdef IPSEC_DEBUG + printf("key_add: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } @@ -4774,7 +4104,120 @@ key_add(mhp) } } -struct sadb_msg * +static int +key_setident(sah, mhp) + struct secashead *sah; + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_ident *idsrc, *iddst; + int idsrclen, iddstlen; + + /* sanity check */ + if (sah == NULL || mhp == NULL || mhp[0] == NULL) + panic("key_setident: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* don't make buffer if not there */ + if (mhp[SADB_EXT_IDENTITY_SRC] == NULL + && mhp[SADB_EXT_IDENTITY_DST] == NULL) { + sah->idents = NULL; + sah->identd = NULL; + return 0; + } + + if (mhp[SADB_EXT_IDENTITY_SRC] == NULL + || mhp[SADB_EXT_IDENTITY_DST] == NULL) { +#ifdef IPSEC_DEBUG + printf("key_setident: invalid identity.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return -1; + } + + idsrc = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC]; + iddst = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST]; + idsrclen = PFKEY_UNUNIT64(idsrc->sadb_ident_len); + iddstlen = PFKEY_UNUNIT64(idsrc->sadb_ident_len); + + /* validity check */ + if (idsrc->sadb_ident_type != iddst->sadb_ident_type) { +#ifdef IPSEC_DEBUG + printf("key_setident: ident type mismatch.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return -1; + } + + switch (idsrc->sadb_ident_type) { + case SADB_X_IDENTTYPE_ADDR: + if (idsrclen != + sizeof(*idsrc) + ((struct sockaddr *)(idsrc + 1))->sa_len + || iddstlen != + sizeof(*iddst) + ((struct sockaddr *)(iddst + 1))->sa_len) { +#ifdef IPSEC_DEBUG + printf("key_setident: invalid length is passed.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return -1; + } + if (((struct sockaddr *)(idsrc + 1))->sa_len > + sizeof(struct sockaddr_storage) + || ((struct sockaddr *)(iddst + 1))->sa_len > + sizeof(struct sockaddr_storage)) { +#ifdef IPSEC_DEBUG + printf("key_setident: invalid sa_len is passed.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return -1; + } +#define __IDENTXID(a) ((union sadb_x_ident_id *)&(a)->sadb_ident_id) + if (__IDENTXID(idsrc)->sadb_x_ident_id_addr.ul_proto + != __IDENTXID(iddst)->sadb_x_ident_id_addr.ul_proto) { +#ifdef IPSEC_DEBUG + printf("key_setident: ul_proto mismatch.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return -1; + } +#undef __IDENTXID(a) + break; + case SADB_IDENTTYPE_PREFIX: + case SADB_IDENTTYPE_FQDN: + case SADB_IDENTTYPE_USERFQDN: + default: + /* XXX do nothing */ + sah->idents = NULL; + sah->identd = NULL; + return 0; + } + + /* make structure */ + KMALLOC(sah->idents, struct sadb_ident *, idsrclen); + if (sah->idents == NULL) { +#ifdef IPSEC_DEBUG + printf("key_setident: No more memory.\n"); +#endif + msg0->sadb_msg_errno = ENOBUFS; + return -1; + } + KMALLOC(sah->identd, struct sadb_ident *, iddstlen); + if (sah->identd == NULL) { + KFREE(sah->idents); +#ifdef IPSEC_DEBUG + printf("key_setident: No more memory.\n"); +#endif + msg0->sadb_msg_errno = ENOBUFS; + return -1; + } + bcopy(idsrc, sah->idents, idsrclen); + bcopy(iddst, sah->identd, iddstlen); + + return 0; +} + +static struct sadb_msg * key_getmsgbuf_x1(mhp) caddr_t *mhp; { @@ -4794,12 +4237,14 @@ key_getmsgbuf_x1(mhp) + sizeof(struct sadb_sa) + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]) - + (mhp[SADB_EXT_ADDRESS_PROXY] == NULL - ? 0 : PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_PROXY])) + (mhp[SADB_EXT_LIFETIME_HARD] == NULL ? 0 : sizeof(struct sadb_lifetime)) + (mhp[SADB_EXT_LIFETIME_SOFT] == NULL - ? 0 : sizeof(struct sadb_lifetime)); + ? 0 : sizeof(struct sadb_lifetime)) + + (mhp[SADB_EXT_IDENTITY_SRC] == NULL + ? 0 : PFKEY_EXTLEN(mhp[SADB_EXT_IDENTITY_SRC])) + + (mhp[SADB_EXT_IDENTITY_DST] == NULL + ? 0 : PFKEY_EXTLEN(mhp[SADB_EXT_IDENTITY_DST])); KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) @@ -4811,18 +4256,20 @@ key_getmsgbuf_x1(mhp) newmsg->sadb_msg_len = PFKEY_UNIT64(len); p = (caddr_t)newmsg + sizeof(*msg0); - p = key_copysadbext(p, mhp[SADB_EXT_SA]); - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_DST]); - - if (mhp[SADB_EXT_ADDRESS_PROXY] != NULL) - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_PROXY]); + p = key_setsadbext(p, mhp[SADB_EXT_SA]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); if (mhp[SADB_EXT_LIFETIME_HARD] != NULL) - p = key_copysadbext(p, mhp[SADB_EXT_LIFETIME_HARD]); + p = key_setsadbext(p, mhp[SADB_EXT_LIFETIME_HARD]); if (mhp[SADB_EXT_LIFETIME_SOFT] != NULL) - p = key_copysadbext(p, mhp[SADB_EXT_LIFETIME_SOFT]); + p = key_setsadbext(p, mhp[SADB_EXT_LIFETIME_SOFT]); + + if (mhp[SADB_EXT_IDENTITY_SRC] != NULL) + p = key_setsadbext(p, mhp[SADB_EXT_IDENTITY_SRC]); + if (mhp[SADB_EXT_IDENTITY_DST] != NULL) + p = key_setsadbext(p, mhp[SADB_EXT_IDENTITY_DST]); return newmsg; } @@ -4847,9 +4294,10 @@ key_delete(mhp) struct sadb_msg *msg0; struct sadb_sa *sa0; struct sadb_address *src0, *dst0; - struct secindex idx; - struct secasindex *saidx; - struct secas *sa; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; /* sanity check */ if (mhp == NULL || mhp[0] == NULL) @@ -4857,10 +4305,21 @@ key_delete(mhp) msg0 = (struct sadb_msg *)mhp[0]; + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { +#ifdef IPSEC_DEBUG + printf("key_delete: invalid satype is passed.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + if (mhp[SADB_EXT_SA] == NULL || mhp[SADB_EXT_ADDRESS_SRC] == NULL || mhp[SADB_EXT_ADDRESS_DST] == NULL) { +#ifdef IPSEC_DEBUG printf("key_delete: invalid message is passed.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; } @@ -4868,30 +4327,30 @@ key_delete(mhp) src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - /* get a SA index */ - if (key_setsecidx(src0, dst0, &idx, 0)) { - msg0->sadb_msg_errno = EINVAL; - return NULL; - } - if ((saidx = key_getsaidxfromany(&idx)) == NULL) { - printf("key_delete: no SA index found.\n"); + KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); + + /* get a SA header */ + if ((sah = key_getsah(&saidx)) == NULL) { +#ifdef IPSEC_DEBUG + printf("key_delete: no SA found.\n"); +#endif msg0->sadb_msg_errno = ENOENT; return NULL; } /* get a SA with SPI. */ - sa = key_getsabyspi(saidx, - msg0->sadb_msg_satype, - sa0->sadb_sa_spi); - if (sa == NULL) { + sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); + if (sav == NULL) { +#ifdef IPSEC_DEBUG printf("key_delete: no alive SA found.\n"); +#endif msg0->sadb_msg_errno = ENOENT; return NULL; } - key_sa_chgstate(sa, SADB_SASTATE_DEAD); - key_freesa(sa); - sa = NULL; + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; { struct sadb_msg *newmsg; @@ -4906,7 +4365,9 @@ key_delete(mhp) KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) { +#ifdef IPSEC_DEBUG printf("key_delete: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } @@ -4917,9 +4378,9 @@ key_delete(mhp) newmsg->sadb_msg_len = PFKEY_UNIT64(len); p = (caddr_t)newmsg + sizeof(*msg0); - p = key_copysadbext(p, mhp[SADB_EXT_SA]); - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); - p = key_copysadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + p = key_setsadbext(p, mhp[SADB_EXT_SA]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); return newmsg; } @@ -4946,9 +4407,10 @@ key_get(mhp) struct sadb_msg *msg0; struct sadb_sa *sa0; struct sadb_address *src0, *dst0; - struct secindex idx; - struct secasindex *saidx; - struct secas *sa; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; /* sanity check */ if (mhp == NULL || mhp[0] == NULL) @@ -4956,10 +4418,21 @@ key_get(mhp) msg0 = (struct sadb_msg *)mhp[0]; + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { +#ifdef IPSEC_DEBUG + printf("key_get: invalid satype is passed.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + if (mhp[SADB_EXT_SA] == NULL || mhp[SADB_EXT_ADDRESS_SRC] == NULL || mhp[SADB_EXT_ADDRESS_DST] == NULL) { +#ifdef IPSEC_DEBUG printf("key_get: invalid message is passed.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; } @@ -4967,23 +4440,23 @@ key_get(mhp) src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - /* get a SA index */ - if (key_setsecidx(src0, dst0, &idx, 0)) { - msg0->sadb_msg_errno = EINVAL; - return NULL; - } - if ((saidx = key_getsaidxfromany(&idx)) == NULL) { - printf("key_get: no SA index found.\n"); + KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); + + /* get a SA header */ + if ((sah = key_getsah(&saidx)) == NULL) { +#ifdef IPSEC_DEBUG + printf("key_get: no SA found.\n"); +#endif msg0->sadb_msg_errno = ENOENT; return NULL; } /* get a SA with SPI. */ - sa = key_getsabyspi(saidx, - msg0->sadb_msg_satype, - sa0->sadb_sa_spi); - if (sa == NULL) { + sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); + if (sav == NULL) { +#ifdef IPSEC_DEBUG printf("key_get: no SA with state of mature found.\n"); +#endif msg0->sadb_msg_errno = ENOENT; return NULL; } @@ -4991,22 +4464,32 @@ key_get(mhp) { struct sadb_msg *newmsg; u_int len; + u_int8_t satype; + + /* map proto to satype */ + if ((satype = key_proto2satype(sah->saidx.proto)) == 0) { +#ifdef IPSEC_DEBUG + printf("key_get: there was invalid proto in SAD.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return NULL; + } /* calculate a length of message buffer */ - len = key_getmsglen(sa); + len = key_getmsglen(sav); KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) { +#ifdef IPSEC_DEBUG printf("key_get: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } /* create new sadb_msg to reply. */ - (void)key_setdumpsa(sa, newmsg); - newmsg->sadb_msg_type = SADB_GET; - newmsg->sadb_msg_seq = msg0->sadb_msg_seq; - newmsg->sadb_msg_pid = msg0->sadb_msg_pid; + (void)key_setdumpsa(newmsg, sav, SADB_GET, + satype, msg0->sadb_msg_seq, msg0->sadb_msg_pid); return newmsg; } @@ -5023,81 +4506,38 @@ key_get(mhp) * with SADB_GETSPI * from KMD by PF_KEY. * - * identity is not supported, must be to do. * sensitivity is not supported. * - * XXX: How can I do process to acquire for tunnel mode. XXX - * * OUT: * 0 : succeed * others: error number */ static int -key_acquire(idx, proto, proxy) - struct secindex *idx; - u_int proto; - struct sockaddr *proxy; +key_acquire(saidx, spidx) + struct secasindex *saidx; + struct secpolicyindex *spidx; { #ifndef IPSEC_NONBLOCK_ACQUIRE struct secacq *newacq; #endif -#if 0 - const char *fqdn = NULL; - const char *userfqdn = NULL; -#endif -#if 0 /* XXX Do it ?*/ - u_int16_t idexttype; -#endif -#ifdef RESTRICTED_DIR - u_int dir; -#endif + u_int8_t satype; int error; /* sanity check */ - if (idx == NULL) + if (saidx == NULL || spidx == NULL) panic("key_acquire: NULL pointer is passed.\n"); + if ((satype = key_proto2satype(saidx->proto)) == 0) + panic("key_acquire: invalid proto is passed.\n"); -#ifdef RESTRICTED_DIR - /* check the direciton. */ - dir = key_checkdir(idx, NULL); - switch (dir) { - case SADB_X_DIR_OUTBOUND: - case SADB_X_DIR_BIDIRECT: - break; - case SADB_X_DIR_INBOUND: /* XXX Move it if you need to kick IKE - * by inbound packet. */ - case SADB_X_DIR_INVALID: - printf("key_acquire: Invalid SA direction.\n"); - return EINVAL; - default: - panic("key_acquire: unexpected direction.\n"); - } -#endif - -#if 0 /* XXX Do it ?*/ - switch (dir) { - case SADB_X_DIR_OUTBOUND: - idexttype = SADB_EXT_IDENTITY_SRC; - break; - case SADB_X_DIR_INBOUND: /* XXX <-- ? */ - idexttype = SADB_EXT_IDENTITY_DST; - break; - default: - idexttype = 0; - break; - } -#endif - +#ifndef IPSEC_NONBLOCK_ACQUIRE /* * We never do anything about acquirng SA. There is anather * solution that kernel blocks to send SADB_ACQUIRE message until * getting something message from IKEd. In later case, to be * managed with ACQUIRING list. */ -#ifndef IPSEC_NONBLOCK_ACQUIRE - /* get a entry to check whether sending message or not. */ - if ((newacq = key_getacq(idx, proto, proxy)) != NULL) { + if ((newacq = key_getacq(saidx)) != NULL) { if (key_blockacq_count < newacq->count) { /* reset counter and do send message. */ newacq->count = 0; @@ -5108,50 +4548,38 @@ key_acquire(idx, proto, proxy) } } else { /* make new entry for blocking to send SADB_ACQUIRE. */ - if ((newacq = key_newacq(idx, proto, proxy)) == NULL) + if ((newacq = key_newacq(saidx)) == NULL) return ENOBUFS; /* add to acqtree */ - key_insnode(&acqtree, NULL, newacq); + LIST_INSERT_HEAD(&acqtree, newacq, chain); } #endif { struct sadb_msg *newmsg = NULL; + union sadb_x_ident_id id; u_int len; caddr_t p; /* create new sadb_msg to reply. */ len = sizeof(struct sadb_msg) + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(idx->family)) + + PFKEY_ALIGN8(saidx->src.ss_len) + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(idx->family)) + + PFKEY_ALIGN8(saidx->dst.ss_len) + + sizeof(struct sadb_ident) + + PFKEY_ALIGN8(spidx->src.ss_len) + + sizeof(struct sadb_ident) + + PFKEY_ALIGN8(spidx->dst.ss_len) + sizeof(struct sadb_prop) + sizeof(struct sadb_comb); /* XXX to be multiple */ -#if 0 /* XXX Do it ?*/ - /* NOTE: +1 is for terminating NUL */ - fqdn = key_getfqdn(); - userfqdn = key_getuserfqdn(); - if (idexttype) { - if (fqdn) - len += (sizeof(struct sadb_ident) - + PFKEY_ALIGN8(strlen(fqdn) + 1)); - len += sizeof(struct sadb_ident); - if (userfqdn) - len += PFKEY_ALIGN8(strlen(userfqdn) + 1); - } -#endif - - /* adding proxy's sockaddr length, if present.*/ - if (proxy != NULL) { - len += (sizeof(struct sadb_address) + - PFKEY_ALIGN8(_SALENBYAF(proxy->sa_family))); - } KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == 0) { +#ifdef IPSEC_DEBUG printf("key_acquire: No more memory.\n"); +#endif return ENOBUFS; } bzero((caddr_t)newmsg, len); @@ -5159,8 +4587,10 @@ key_acquire(idx, proto, proxy) newmsg->sadb_msg_version = PF_KEY_V2; newmsg->sadb_msg_type = SADB_ACQUIRE; newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_satype = proto; + newmsg->sadb_msg_satype = satype; newmsg->sadb_msg_len = PFKEY_UNIT64(len); + newmsg->sadb_msg_mode = saidx->mode; + newmsg->sadb_msg_reqid = saidx->reqid; #ifndef IPSEC_NONBLOCK_ACQUIRE newmsg->sadb_msg_seq = newacq->seq; @@ -5171,31 +4601,38 @@ key_acquire(idx, proto, proxy) newmsg->sadb_msg_pid = 0; p = (caddr_t)newmsg + sizeof(struct sadb_msg); - /* set sadb_address for source */ - p = key_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, - idx->family, - (caddr_t)&idx->src, - idx->prefs, - idx->proto, - idx->ports); + /* set sadb_address for saidx's. */ + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&saidx->src, + _INALENBYAF(saidx->src.ss_family) << 3, + IPSEC_ULPROTO_ANY); + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&saidx->dst, + _INALENBYAF(saidx->dst.ss_family) << 3, + IPSEC_ULPROTO_ANY); - /* set sadb_address for destination */ - p = key_setsadbaddr(p, SADB_EXT_ADDRESS_DST, - idx->family, - (caddr_t)&idx->dst, - idx->prefd, - idx->proto, - idx->portd); + /* set sadb_address for spidx's. */ + bzero(&id, sizeof(id)); + id.sadb_x_ident_id_addr.prefix = spidx->prefs; + id.sadb_x_ident_id_addr.ul_proto = spidx->ul_proto; + p = key_setsadbident(p, + SADB_EXT_IDENTITY_SRC, + SADB_X_IDENTTYPE_ADDR, + (caddr_t)&spidx->src, + spidx->src.ss_len, + *(u_int64_t *)&id); - /* set sadb_address for proxy, if exists. */ - if (proxy != NULL) { - p = key_setsadbaddr(p, SADB_EXT_ADDRESS_PROXY, - proxy->sa_family, - _INADDRBYSA(proxy), - _INALENBYAF(proxy->sa_family), - 0, - 0); - } + bzero(&id, sizeof(id)); + id.sadb_x_ident_id_addr.prefix = spidx->prefd; + id.sadb_x_ident_id_addr.ul_proto = spidx->ul_proto; + p = key_setsadbident(p, + SADB_EXT_IDENTITY_DST, + SADB_X_IDENTTYPE_ADDR, + (caddr_t)&spidx->dst, + spidx->dst.ss_len, + *(u_int64_t *)&id); /* create proposal extension */ /* set combination extension */ @@ -5272,51 +4709,35 @@ key_acquire(idx, proto, proxy) #endif error = key_sendall(newmsg, len); +#ifdef IPSEC_DEBUG if (error != 0) printf("key_acquire: key_sendall returned %d\n", error); +#endif return error; } return 0; } +#ifndef IPSEC_NONBLOCK_ACQUIRE static struct secacq * -key_newacq(idx, proto, proxy) - struct secindex *idx; - u_int proto; - struct sockaddr *proxy; +key_newacq(saidx) + struct secasindex *saidx; { struct secacq *newacq; /* get new entry */ KMALLOC(newacq, struct secacq *, sizeof(struct secacq)); if (newacq == NULL) { +#ifdef IPSEC_DEBUG printf("key_newacq: No more memory.\n"); +#endif return NULL; } bzero(newacq, sizeof(*newacq)); -#if 1 /* copy secindex */ - newacq->idx.family = idx->family; - newacq->idx.prefs = idx->prefs; - newacq->idx.prefd = idx->prefd; - newacq->idx.proto = idx->proto; - newacq->idx.ports = idx->ports; - newacq->idx.portd = idx->portd; - bcopy(&idx->src, &newacq->idx.src, _INALENBYAF(idx->family)); - bcopy(&idx->dst, &newacq->idx.dst, _INALENBYAF(idx->family)); - - newacq->proto = proto; - - if (proxy != NULL) - bcopy(_INADDRBYSA(proxy), newacq->proxy, sizeof(newacq->proxy)); - else - bzero(&newacq->proxy, sizeof(newacq->proxy)); -#else - /* XXX to use HASH may be enough to manage. */ - SOME_HASH_FUNCTION(newacq->hash, idx|proto|proxy); -#endif + bcopy(saidx, &newacq->saidx, sizeof(newacq->saidx)); newacq->seq = (acq_seq == ~0 ? 1 : ++acq_seq); newacq->tick = 0; newacq->count = 0; @@ -5324,50 +4745,14 @@ key_newacq(idx, proto, proxy) return newacq; } -static void -key_delacq(acq) - struct secacq *acq; -{ - /* sanity check */ - if (acq == NULL) - panic("key_delacq: NULL pointer is passed.\n"); - - key_remnode(acq); - KFREE(acq); - - return; -} - static struct secacq * -key_getacq(idx, proto, proxy) - struct secindex *idx; - u_int proto; - struct sockaddr *proxy; +key_getacq(saidx) + struct secasindex *saidx; { struct secacq *acq; - for (acq = (struct secacq *)acqtree.head; - acq != NULL; - acq = acq->next) { - - if (acq->proto != proto) - continue; - if (!key_cmpidx(&acq->idx, idx)) - continue; - { - int i; - for (i = 0; i < sizeof(acq->proxy); i++) { - if (acq->proxy[i] != 0) - break; - } - if (i == sizeof(acq->proxy) && proxy == NULL) - return acq; - if (i == sizeof(acq->proxy) && proxy != NULL) - continue; - } - - if (proxy != NULL - && !bcmp(&acq->proxy, _INADDRBYSA(proxy), sizeof(acq->proxy))) + LIST_FOREACH(acq, &acqtree, chain) { + if (key_cmpsaidx_exactly(saidx, &acq->saidx)) return acq; } @@ -5380,22 +4765,20 @@ key_getacqbyseq(seq) { struct secacq *acq; - for (acq = (struct secacq *)acqtree.head; - acq != NULL; - acq = acq->next) { - + LIST_FOREACH(acq, &acqtree, chain) { if (acq->seq == seq) return acq; } return NULL; } +#endif /* * SADB_ACQUIRE processing, * in first situation, is receiving * - * from the ikmpd, and clear sequence of its secas entry. + * from the ikmpd, and clear sequence of its secasvar entry. * * In second situation, is receiving * @@ -5413,12 +4796,9 @@ key_acquire2(mhp) { struct sadb_msg *msg0; struct sadb_address *src0, *dst0; - struct sockaddr *proxy; - struct secindex idx; - struct secasindex *saidx; -#ifdef RESTRICTED_DIR - u_int dir; -#endif + struct secasindex saidx; + struct secashead *sah; + u_int16_t proto; /* sanity check */ if (mhp == NULL || mhp[0] == NULL) @@ -5426,80 +4806,84 @@ key_acquire2(mhp) msg0 = (struct sadb_msg *)mhp[0]; - /* Is it a error message from KMd ? */ /* - * It must be just size of sadb_msg structure if error was occured - * by IKEd. + * Error message from KMd. + * We assume that if error was occured in IKEd, the length of PFKEY + * message is equal to the size of sadb_msg structure. + * We return ~0 even if error occured in this function. */ if (msg0->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) { - /* XXX To be managed with ACQUIRING list ? */ +#ifndef IPSEC_NONBLOCK_ACQUIRE + struct secacq *acq; - return (struct sadb_msg *)~0; /* exit as normal status */ + /* check sequence number */ + if (msg0->sadb_msg_seq == 0) { +#ifdef IPSEC_DEBUG + printf("key_acquire2: must specify sequence number.\n"); +#endif + return (struct sadb_msg *)~0; + } + if ((acq = key_getacqbyseq(msg0->sadb_msg_seq)) == NULL) { +#ifdef IPSEC_DEBUG + printf("key_acquire2: " + "invalid sequence number is passed.\n"); +#endif + return (struct sadb_msg *)~0; + } + + /* reset acq counter in order to deletion by timehander. */ + acq->tick = key_blockacq_lifetime; + acq->count = 0; +#endif + return (struct sadb_msg *)~0; /* NOTREACHED */ } - /* Is this a acquire message from user land ? */ + /* + * This message is from user land. + */ + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { +#ifdef IPSEC_DEBUG + printf("key_acquire2: invalid satype is passed.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL || mhp[SADB_EXT_ADDRESS_DST] == NULL || mhp[SADB_EXT_PROPOSAL] == NULL) { /* error */ +#ifdef IPSEC_DEBUG printf("key_acquire2: invalid message is passed.\n"); +#endif msg0->sadb_msg_errno = EINVAL; return NULL; } src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - if (mhp[SADB_EXT_ADDRESS_PROXY] == NULL) - proxy = NULL; - else - proxy = (struct sockaddr *)(mhp[SADB_EXT_ADDRESS_PROXY] - + sizeof(struct sadb_address)); - /* make secindex */ - if (key_setsecidx(src0, dst0, &idx, 0)) { - msg0->sadb_msg_errno = EINVAL; - return NULL; - } - -#ifdef RESTRICTED_DIR - /* checking the direciton. */ - dir = key_checkdir(&idx, proxy); - switch (dir) { - case SADB_X_DIR_INBOUND: - case SADB_X_DIR_BIDIRECT: - case SADB_X_DIR_OUTBOUND: - /* XXX What I do ? */ - break; - case SADB_X_DIR_INVALID: - printf("key_acquire2: Invalid SA direction.\n"); - msg0->sadb_msg_errno = EINVAL; - return NULL; - default: - panic("key_acquire2: unexpected direction %u", dir); - } -#endif + KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); /* get a SA index */ -#ifdef RESTRICTED_DIR - if ((saidx = key_getsaidx(&idx, dir)) != NULL) { + if ((sah = key_getsah(&saidx)) != NULL) { +#ifdef IPSEC_DEBUG printf("key_acquire2: a SA exists already.\n"); - msg0->sadb_msg_errno = EEXIST; - return NULL; - } -#else - if ((saidx = key_getsaidx(&idx)) != NULL) { - printf("key_acquire2: a SA exists already.\n"); - msg0->sadb_msg_errno = EEXIST; - return NULL; - } #endif + msg0->sadb_msg_errno = EEXIST; + return NULL; + } - msg0->sadb_msg_errno = key_acquire(&idx, msg0->sadb_msg_satype, proxy); + msg0->sadb_msg_errno = key_acquire(&saidx, NULL); if (msg0->sadb_msg_errno != 0) { - /* XXX What I do ? */ - printf("key_acquire2: error occured.\n"); +#ifdef IPSEC_DEBUG + printf("key_acquire2: error %d returned " + "from key_acquire.\n", msg0->sadb_msg_errno); +#endif return NULL; } @@ -5512,7 +4896,9 @@ key_acquire2(mhp) KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) { +#ifdef IPSEC_DEBUG printf("key_acquire2: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } @@ -5525,7 +4911,8 @@ key_acquire2(mhp) } /* - * SADB_REGISTER processing + * SADB_REGISTER processing. + * If SATYPE_UNSPEC has been passed as satype, only return sabd_supported. * receive * * from the ikmpd, and register a socket to send PF_KEY messages, @@ -5551,15 +4938,22 @@ key_register(mhp, so) msg0 = (struct sadb_msg *)mhp[0]; + /* check for invalid register message */ + if (msg0->sadb_msg_satype >= sizeof(regtree)/sizeof(regtree[0])) { + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + /* When SATYPE_UNSPEC is specified, only return sabd_supported. */ if (msg0->sadb_msg_satype == SADB_SATYPE_UNSPEC) goto setmsg; /* check whether existing or not */ - reg = (struct secreg *)regtree[msg0->sadb_msg_satype].head; - for (; reg != NULL; reg = reg->next) { + LIST_FOREACH(reg, ®tree[msg0->sadb_msg_satype], chain) { if (reg->so == so) { +#ifdef IPSEC_DEBUG printf("key_register: socket exists already.\n"); +#endif msg0->sadb_msg_errno = EEXIST; return NULL; } @@ -5568,7 +4962,9 @@ key_register(mhp, so) /* create regnode */ KMALLOC(newreg, struct secreg *, sizeof(struct secreg)); if (newreg == NULL) { +#ifdef IPSEC_DEBUG printf("key_register: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } @@ -5578,9 +4974,9 @@ key_register(mhp, so) ((struct keycb *)sotorawcb(so))->kp_registered++; /* add regnode to regtree. */ - key_insnode(®tree[msg0->sadb_msg_satype], NULL, newreg); + LIST_INSERT_HEAD(®tree[msg0->sadb_msg_satype], newreg, chain); - setmsg: + setmsg: { struct sadb_msg *newmsg; struct sadb_supported *sup; @@ -5604,7 +5000,9 @@ key_register(mhp, so) KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) { +#ifdef IPSEC_DEBUG printf("key_register: No more memory.\n"); +#endif msg0->sadb_msg_errno = ENOBUFS; return NULL; } @@ -5688,12 +5086,16 @@ key_freereg(so) if (so == NULL) panic("key_freereg: NULL pointer is passed.\n"); - /* check whether existing or not */ + /* + * check whether existing or not. + * check all type of SA, because there is a potential that + * one socket is registered to multiple type of SA. + */ for (i = 0; i <= SADB_SATYPE_MAX; i++) { - reg = (struct secreg *)regtree[i].head; - for (; reg; reg = reg->next) { - if (reg->so == so) { - key_remnode(reg); + LIST_FOREACH(reg, ®tree[i], chain) { + if (reg->so == so + && __LIST_CHAINED(reg)) { + LIST_REMOVE(reg, chain); KFREE(reg); break; } @@ -5714,24 +5116,22 @@ key_freereg(so) * others : error number */ static int -key_expire(sa) - struct secas *sa; +key_expire(sav) + struct secasvar *sav; { int s; + int satype; -#ifdef __NetBSD__ + /* XXX: Why do we lock ? */ s = splsoftnet(); /*called from softclock()*/ -#else - s = splnet(); /*called from softclock()*/ -#endif /* sanity check */ - if (sa == NULL) + if (sav == NULL) panic("key_expire: NULL pointer is passed.\n"); - - /* sanity check 2 */ - if (sa->saidx == NULL) + if (sav->sah == NULL) panic("key_expire: Why was SA index in SA NULL.\n"); + if ((satype = key_proto2satype(sav->sah->saidx.proto)) == 0) + panic("key_expire: invalid proto is passed.\n"); { struct sadb_msg *newmsg = NULL; @@ -5745,77 +5145,59 @@ key_expire(sa) + sizeof(struct sadb_lifetime) + sizeof(struct sadb_lifetime) + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(sa->saidx->idx.family)) + + PFKEY_ALIGN8(sav->sah->saidx.src.ss_len) + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(sa->saidx->idx.family)); + + PFKEY_ALIGN8(sav->sah->saidx.dst.ss_len); KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) { +#ifdef IPSEC_DEBUG printf("key_expire: No more memory.\n"); +#endif splx(s); return ENOBUFS; } bzero((caddr_t)newmsg, len); - newmsg->sadb_msg_version = PF_KEY_V2; - newmsg->sadb_msg_type = SADB_EXPIRE; - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_satype = sa->type; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - newmsg->sadb_msg_seq = sa->seq; - newmsg->sadb_msg_pid = 0; - p = (caddr_t)newmsg + sizeof(struct sadb_msg); + /* set msg header */ + p = key_setsadbmsg((caddr_t)newmsg, SADB_EXPIRE, len, + satype, sav->seq, 0, + sav->sah->saidx.mode, sav->sah->saidx.reqid, + 0, sav->refcnt); /* create SA extension */ - { - struct sadb_sa *m_sa; - - m_sa = (struct sadb_sa *)p; - m_sa->sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa)); - m_sa->sadb_sa_exttype = SADB_EXT_SA; - m_sa->sadb_sa_spi = sa->spi; - m_sa->sadb_sa_replay = (sa->replay ? sa->replay->wsize : NULL); - /*XXX: unit?*/ - m_sa->sadb_sa_state = sa->state; - m_sa->sadb_sa_auth = sa->alg_auth; - m_sa->sadb_sa_encrypt = sa->alg_enc; - m_sa->sadb_sa_flags = sa->flags; - p += sizeof(struct sadb_sa); - } + p = key_setsadbsa(p, sav); /* create lifetime extension */ { - struct sadb_lifetime *m_lt; + struct sadb_lifetime *m_lt = (struct sadb_lifetime *)p; - m_lt = (struct sadb_lifetime *)p; m_lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); m_lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; - m_lt->sadb_lifetime_allocations = sa->lft_c->sadb_lifetime_allocations; - m_lt->sadb_lifetime_bytes = sa->lft_c->sadb_lifetime_bytes; - m_lt->sadb_lifetime_addtime = sa->lft_c->sadb_lifetime_addtime; - m_lt->sadb_lifetime_usetime = sa->lft_c->sadb_lifetime_usetime; + m_lt->sadb_lifetime_allocations = sav->lft_c->sadb_lifetime_allocations; + m_lt->sadb_lifetime_bytes = sav->lft_c->sadb_lifetime_bytes; + m_lt->sadb_lifetime_addtime = sav->lft_c->sadb_lifetime_addtime; + m_lt->sadb_lifetime_usetime = sav->lft_c->sadb_lifetime_usetime; p += sizeof(struct sadb_lifetime); /* copy SOFT lifetime extension. */ - bcopy(sa->lft_s, p, sizeof(struct sadb_lifetime)); + bcopy(sav->lft_s, p, sizeof(struct sadb_lifetime)); p += sizeof(struct sadb_lifetime); } /* set sadb_address for source */ - p = key_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, - sa->saidx->idx.family, - (caddr_t)&sa->saidx->idx.src, - sa->saidx->idx.prefs, - sa->saidx->idx.proto, - sa->saidx->idx.ports); + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sav->sah->saidx.src, + _INALENBYAF(sav->sah->saidx.src.ss_family) << 3, + IPSEC_ULPROTO_ANY); /* set sadb_address for destination */ - p = key_setsadbaddr(p, SADB_EXT_ADDRESS_DST, - sa->saidx->idx.family, - (caddr_t)&sa->saidx->idx.dst, - sa->saidx->idx.prefd, - sa->saidx->idx.proto, - sa->saidx->idx.portd); + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sav->sah->saidx.dst, + _INALENBYAF(sav->sah->saidx.dst.ss_family) << 3, + IPSEC_ULPROTO_ANY); error = key_sendall(newmsg, len); splx(s); @@ -5842,9 +5224,11 @@ key_flush(mhp) caddr_t *mhp; { struct sadb_msg *msg0; - struct secasindex *saidx; - struct secas *sa, *sanext; /* for save */ - u_int state; + struct secashead *sah, *nextsah; + struct secasvar *sav, *nextsav; + u_int16_t proto; + u_int8_t state; + u_int stateidx; /* sanity check */ if (mhp == NULL || mhp[0] == NULL) @@ -5852,30 +5236,44 @@ key_flush(mhp) msg0 = (struct sadb_msg *)mhp[0]; + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { +#ifdef IPSEC_DEBUG + printf("key_flush: invalid satype is passed.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + /* no SATYPE specified, i.e. flushing all SA. */ - KEY_SADBLOOP( - /* - * no need to flush DEAD SAs, - * they are already dead! - */ - if (state == SADB_SASTATE_DEAD) + for (sah = LIST_FIRST(&sahtree); + sah != NULL; + sah = nextsah) { + + nextsah = LIST_NEXT(sah, chain); + + if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + && proto != sah->saidx.proto) continue; - for (sa = (struct secas *)saidx->satree[state].head; - sa != NULL; - sa = sanext) { + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_alive); + stateidx++) { - sanext = sa->next; /* save */ + state = saorder_state_any[stateidx]; + for (sav = LIST_FIRST(&sah->savtree[state]); + sav != NULL; + sav = nextsav) { - if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC - && msg0->sadb_msg_satype != sa->type) - continue; + nextsav = LIST_NEXT(sav, chain); - key_sa_chgstate(sa, SADB_SASTATE_DEAD); - key_freesa(sa); - sa = NULL; + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + } } - ); + + sah->state = SADB_SASTATE_DEAD; + } { struct sadb_msg *newmsg; @@ -5886,7 +5284,10 @@ key_flush(mhp) KMALLOC(newmsg, struct sadb_msg *, len); if (newmsg == NULL) { +#ifdef IPSEC_DEBUG printf("key_flush: No more memory.\n"); +#endif + msg0->sadb_msg_errno = ENOBUFS; return NULL; } bzero((caddr_t)newmsg, len); @@ -5901,9 +5302,10 @@ key_flush(mhp) /* * SADB_DUMP processing + * dump all entries including status of DEAD in SAD. * receive * - * from the ikmpd, and dump all secas leaves + * from the ikmpd, and dump all secasvar leaves * and send, * ..... * to the ikmpd. @@ -5918,9 +5320,12 @@ key_dump(mhp, so, target) int target; { struct sadb_msg *msg0; - struct secas *sa; - struct secasindex *saidx; - u_int state; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; + u_int stateidx; + u_int8_t satype; + u_int8_t state; int len, cnt; struct sadb_msg *newmsg; @@ -5930,53 +5335,81 @@ key_dump(mhp, so, target) msg0 = (struct sadb_msg *)mhp[0]; - /* count sa entries to be sent to the userland. */ + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { +#ifdef IPSEC_DEBUG + printf("key_dump: invalid satype is passed.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* count sav entries to be sent to the userland. */ cnt = 0; - KEY_SADBLOOP( - for (sa = (struct secas *)saidx->satree[state].head; - sa != NULL; - sa = sa->next) { + LIST_FOREACH(sah, &sahtree, chain) { - if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC - && msg0->sadb_msg_satype != sa->type) - continue; + if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + && proto != sah->saidx.proto) + continue; - cnt++; + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_any); + stateidx++) { + + state = saorder_state_any[stateidx]; + LIST_FOREACH(sav, &sah->savtree[state], chain) { + cnt++; + } } - ); + } if (cnt == 0) return ENOENT; /* send this to the userland, one at a time. */ newmsg = NULL; - KEY_SADBLOOP( - for (sa = (struct secas *)saidx->satree[state].head; - sa != NULL; - sa = sa->next) { + LIST_FOREACH(sah, &sahtree, chain) { - if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC - && msg0->sadb_msg_satype != sa->type) - continue; + if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + && proto != sah->saidx.proto) + continue; - len = key_getmsglen(sa); - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { - printf("key_dump: No more memory.\n"); - return ENOBUFS; - } - bzero((caddr_t)newmsg, len); - - (void)key_setdumpsa(sa, newmsg); - newmsg->sadb_msg_type = SADB_DUMP; - newmsg->sadb_msg_seq = --cnt; - newmsg->sadb_msg_pid = msg0->sadb_msg_pid; - - key_sendup(so, newmsg, len, target); - KFREE(newmsg); - newmsg = NULL; + /* map proto to satype */ + if ((satype = key_proto2satype(sah->saidx.proto)) == 0) { +#ifdef IPSEC_DEBUG + printf("key_dump: there was invalid proto in SAD.\n"); +#endif + msg0->sadb_msg_errno = EINVAL; + return NULL; } - ); + + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_any); + stateidx++) { + + state = saorder_state_any[stateidx]; + LIST_FOREACH(sav, &sah->savtree[state], chain) { + + len = key_getmsglen(sav); + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { +#ifdef IPSEC_DEBUG + printf("key_dump: No more memory.\n"); +#endif + return ENOBUFS; + } + bzero((caddr_t)newmsg, len); + + --cnt; + (void)key_setdumpsa(newmsg, sav, SADB_DUMP, + satype, cnt, msg0->sadb_msg_pid); + + key_sendup(so, newmsg, len, target); + KFREE(newmsg); + newmsg = NULL; + } + } + } return 0; } @@ -6058,7 +5491,7 @@ key_sendall(msg, len) struct sadb_msg *msg; u_int len; { - struct secreg *req; + struct secreg *reg; int error = 0; /* sanity check */ @@ -6066,21 +5499,20 @@ key_sendall(msg, len) panic("key_sendall: NULL pointer is passed.\n"); /* search table registerd socket to send a message. */ - req = (struct secreg *)regtree[msg->sadb_msg_satype].head; - while (req != NULL) { - error = key_sendup(req->so, msg, len, KEY_SENDUP_ONE); + LIST_FOREACH(reg, ®tree[msg->sadb_msg_satype], chain) { + error = key_sendup(reg->so, msg, len, KEY_SENDUP_ONE); if (error != 0) { +#ifdef IPSEC_DEBUG if (error == ENOBUFS) printf("key_sendall: No more memory.\n"); else { printf("key_sendall: key_sendup returned %d\n", error); } +#endif KFREE(msg); return error; } - - req = req->next; } KFREE(msg); @@ -6122,16 +5554,161 @@ key_parse(msgp, so, targetp) if (targetp) *targetp = KEY_SENDUP_ONE; - /* initialization for mhp */ - { - int i; - for (i = 0; i < SADB_EXT_MAX + 1; i++) - mhp[i] = NULL; - } - - /* check message and align. */ - if ((msg->sadb_msg_errno = key_check(msg, mhp)) != 0) + /* check version */ + if (msg->sadb_msg_version != PF_KEY_V2) { +#ifdef IPSEC_DEBUG + printf("key_parse: PF_KEY version %u is mismatched.\n", + msg->sadb_msg_version); +#endif + pfkeystat.out_invver++; + msg->sadb_msg_errno = EINVAL; return orglen; + } + + /* check type */ + if (msg->sadb_msg_type > SADB_MAX) { +#ifdef IPSEC_DEBUG + printf("key_parse: invalid type %u is passed.\n", + msg->sadb_msg_type); +#endif + msg->sadb_msg_errno = EINVAL; + pfkeystat.out_invmsgtype++; + return orglen; + } + + /* align message. */ + if (key_align(msg, mhp) != 0) { + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + /* check SA type */ + switch (msg->sadb_msg_satype) { + case SADB_SATYPE_UNSPEC: + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + case SADB_UPDATE: + case SADB_ADD: + case SADB_DELETE: + case SADB_GET: + case SADB_ACQUIRE: + case SADB_EXPIRE: +#ifdef IPSEC_DEBUG + printf("key_parse: must specify satype " + "when msg type=%u.\n", + msg->sadb_msg_type); +#endif + msg->sadb_msg_errno = EINVAL; + pfkeystat.out_invsatype++; + return orglen; + } + break; + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: +#if 1 /*nonstandard*/ + case SADB_X_SATYPE_IPCOMP: +#endif + switch (msg->sadb_msg_type) { + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + case SADB_X_SPDGET: + case SADB_X_SPDDUMP: + case SADB_X_SPDFLUSH: +#ifdef IPSEC_DEBUG + printf("key_parse: illegal satype=%u\n", + msg->sadb_msg_type); +#endif + msg->sadb_msg_errno = EINVAL; + pfkeystat.out_invsatype++; + return orglen; + } + break; + case SADB_SATYPE_RSVP: + case SADB_SATYPE_OSPFV2: + case SADB_SATYPE_RIPV2: + case SADB_SATYPE_MIP: +#ifdef IPSEC_DEBUG + printf("key_parse: type %u isn't supported.\n", + msg->sadb_msg_satype); +#endif + msg->sadb_msg_errno = EOPNOTSUPP; + pfkeystat.out_invsatype++; + return orglen; + case 1: /* XXX: What does it do ? */ + if (msg->sadb_msg_type == SADB_X_PROMISC) + break; + /*FALLTHROUGH*/ + default: +#ifdef IPSEC_DEBUG + printf("key_parse: invalid type %u is passed.\n", + msg->sadb_msg_satype); +#endif + msg->sadb_msg_errno = EINVAL; + pfkeystat.out_invsatype++; + return orglen; + } + + /* check field of upper layer protocol and address family */ + if (mhp[SADB_EXT_ADDRESS_SRC] != NULL + && mhp[SADB_EXT_ADDRESS_DST] != NULL) { + struct sadb_address *src0, *dst0; + u_int prefix; + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + /* check upper layer protocol */ + if (src0->sadb_address_proto != dst0->sadb_address_proto) { +#ifdef IPSEC_DEBUG + printf("key_parse: upper layer protocol mismatched.\n"); +#endif + msg->sadb_msg_errno = EINVAL; + pfkeystat.out_invaddr++; + return orglen; + } + + /* check family */ + if (PFKEY_ADDR_SADDR(src0)->sa_family + != PFKEY_ADDR_SADDR(dst0)->sa_family) { +#ifdef IPSEC_DEBUG + printf("key_parse: address family mismatched.\n"); +#endif + msg->sadb_msg_errno = EINVAL; + pfkeystat.out_invaddr++; + return orglen; + } + + prefix = _INALENBYAF(PFKEY_ADDR_SADDR(src0)->sa_family) << 3; + + /* check max prefixlen */ + if (prefix < src0->sadb_address_prefixlen + || prefix < dst0->sadb_address_prefixlen) { +#ifdef IPSEC_DEBUG + printf("key_parse: illegal prefixlen.\n"); +#endif + msg->sadb_msg_errno = EINVAL; + pfkeystat.out_invaddr++; + return orglen; + } + + switch (PFKEY_ADDR_SADDR(src0)->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: +#ifdef IPSEC_DEBUG + printf("key_parse: invalid address family.\n"); +#endif + msg->sadb_msg_errno = EINVAL; + pfkeystat.out_invaddr++; + return orglen; + } + + /* + * prefixlen == 0 is valid because there can be a case when + * all addresses are matched. + */ + } switch (msg->sadb_msg_type) { case SADB_GETSPI: @@ -6176,6 +5753,7 @@ key_parse(msgp, so, targetp) * It's not need to reply because of the message * that was reporting an error occured from the KMd. */ + KFREE(msg); return 0; } break; @@ -6195,10 +5773,13 @@ key_parse(msgp, so, targetp) break; case SADB_EXPIRE: +#ifdef IPSEC_DEBUG printf("key_parse: why is SADB_EXPIRE received ?\n"); +#endif msg->sadb_msg_errno = EINVAL; if (targetp) *targetp = KEY_SENDUP_ALL; + pfkeystat.out_invmsgtype++; return orglen; case SADB_FLUSH: @@ -6214,8 +5795,10 @@ key_parse(msgp, so, targetp) if (error) { msg->sadb_msg_errno = error; return orglen; - } else + } else { + KFREE(msg); return 0; + } break; case SADB_X_PROMISC: @@ -6225,8 +5808,11 @@ key_parse(msgp, so, targetp) return 0; /*nothing to reply*/ case SADB_X_PCHANGE: +#ifdef IPSEC_DEBUG printf("key_parse: SADB_X_PCHANGE isn't supported.\n"); +#endif msg->sadb_msg_errno = EINVAL; + pfkeystat.out_invmsgtype++; return orglen; #if 0 if (targetp) @@ -6253,11 +5839,12 @@ key_parse(msgp, so, targetp) if (error) { msg->sadb_msg_errno = error; return orglen; - } else + } else { + KFREE(msg); return 0; + } break; - case SADB_X_SPDFLUSH: if ((newmsg = key_spdflush(mhp)) == NULL) return orglen; @@ -6278,103 +5865,36 @@ key_parse(msgp, so, targetp) } /* - * check basic usage for sadb_msg, - * and set the pointer to each header in this message buffer. + * set the pointer to each header into message buffer. * IN: msg: pointer to message buffer. - * mhp: pointer to the buffer initialized like below: - * + * mhp: pointer to the buffer allocated like below: * caddr_t mhp[SADB_EXT_MAX + 1]; - * - * OUT: 0 if success. - * other if error, return errno. - * + * OUT: 0: + * EINVAL: */ static int -key_check(msg, mhp) +key_align(msg, mhp) struct sadb_msg *msg; caddr_t *mhp; { - /* sanity check */ - if (msg == NULL || mhp == NULL) - panic("key_check: NULL pointer is passed.\n"); - - /* initialize */ - { - int i; - for (i = 0; i < SADB_EXT_MAX + 1; i++) - mhp[i] = NULL; - } - - /* check version */ - if (msg->sadb_msg_version != PF_KEY_V2) { - printf("key_check: PF_KEY version %u is too old.\n", - msg->sadb_msg_version); - return EINVAL; - } - - /* check type */ - if (msg->sadb_msg_type > SADB_MAX) { - printf("key_check: invalid type %u is passed.\n", - msg->sadb_msg_type); - return EINVAL; - } - - /* check SA type */ - switch (msg->sadb_msg_satype) { - case SADB_SATYPE_UNSPEC: - if (msg->sadb_msg_type != SADB_REGISTER - && msg->sadb_msg_type != SADB_FLUSH - && msg->sadb_msg_type != SADB_DUMP - && msg->sadb_msg_type != SADB_X_PROMISC - && msg->sadb_msg_type != SADB_X_SPDADD - && msg->sadb_msg_type != SADB_X_SPDDELETE - && msg->sadb_msg_type != SADB_X_SPDDUMP - && msg->sadb_msg_type != SADB_X_SPDFLUSH) { - printf("key_check: type UNSPEC is invalid.\n"); - return EINVAL; - } - break; - case SADB_SATYPE_AH: - case SADB_SATYPE_ESP: -#if 1 /*nonstandard*/ - case SADB_X_SATYPE_IPCOMP: -#endif - break; - case SADB_SATYPE_RSVP: - case SADB_SATYPE_OSPFV2: - case SADB_SATYPE_RIPV2: - case SADB_SATYPE_MIP: - printf("key_check: type %u isn't supported.\n", - msg->sadb_msg_satype); - return EOPNOTSUPP; - case 1: - if (msg->sadb_msg_type == SADB_X_PROMISC) - break; - /*FALLTHROUGH*/ - default: - printf("key_check: invalid type %u is passed.\n", - msg->sadb_msg_satype); - return EINVAL; - } - - mhp[0] = (caddr_t)msg; - - { struct sadb_ext *ext; int tlen, extlen; + int i; + + /* sanity check */ + if (msg == NULL || mhp == NULL) + panic("key_align: NULL pointer is passed.\n"); + + /* initialize */ + for (i = 0; i < SADB_EXT_MAX + 1; i++) + mhp[i] = NULL; + + mhp[0] = (caddr_t)msg; tlen = PFKEY_UNUNIT64(msg->sadb_msg_len) - sizeof(struct sadb_msg); ext = (struct sadb_ext *)((caddr_t)msg + sizeof(struct sadb_msg)); while (tlen > 0) { - /* duplicate check */ - /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ - if (mhp[ext->sadb_ext_type] != NULL) { - printf("key_check: duplicate ext_type %u is passed.\n", - ext->sadb_ext_type); - return EINVAL; - } - /* set pointer */ switch (ext->sadb_ext_type) { case SADB_EXT_SA: @@ -6385,9 +5905,7 @@ key_check(msg, mhp) case SADB_EXT_ADDRESS_DST: case SADB_EXT_ADDRESS_PROXY: case SADB_EXT_KEY_AUTH: - /* must to be chek weak keys. */ case SADB_EXT_KEY_ENCRYPT: - /* must to be chek weak keys. */ case SADB_EXT_IDENTITY_SRC: case SADB_EXT_IDENTITY_DST: case SADB_EXT_SENSITIVITY: @@ -6396,10 +5914,28 @@ key_check(msg, mhp) case SADB_EXT_SUPPORTED_ENCRYPT: case SADB_EXT_SPIRANGE: case SADB_X_EXT_POLICY: + /* duplicate check */ + /* + * XXX Are there duplication payloads of either + * KEY_AUTH or KEY_ENCRYPT ? + */ + if (mhp[ext->sadb_ext_type] != NULL) { +#ifdef IPSEC_DEBUG + printf("key_align: duplicate ext_type %u " + "is passed.\n", + ext->sadb_ext_type); +#endif + pfkeystat.out_dupext++; + return EINVAL; + } mhp[ext->sadb_ext_type] = (caddr_t)ext; break; default: - printf("key_check: invalid ext_type %u is passed.\n", ext->sadb_ext_type); +#ifdef IPSEC_DEBUG + printf("key_align: invalid ext_type %u is passed.\n", + ext->sadb_ext_type); +#endif + pfkeystat.out_invexttype++; return EINVAL; } @@ -6407,38 +5943,6 @@ key_check(msg, mhp) tlen -= extlen; ext = (struct sadb_ext *)((caddr_t)ext + extlen); } - } - - /* check field of upper layer protocol and address family */ - if (mhp[SADB_EXT_ADDRESS_SRC] != NULL - && mhp[SADB_EXT_ADDRESS_DST] != NULL) { - struct sadb_address *src0, *dst0; - struct sockaddr *src, *dst; - - src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - src = (struct sockaddr *)((caddr_t)src0 + sizeof(*src0)); - dst = (struct sockaddr *)((caddr_t)dst0 + sizeof(*dst0)); - - if (src0->sadb_address_proto != dst0->sadb_address_proto) { - printf("key_check: upper layer protocol mismatched.\n"); - return EINVAL; - } - - if (src->sa_family != dst->sa_family) { - printf("key_check: address family mismatched.\n"); - return EINVAL; - } - if (src->sa_family != AF_INET && src->sa_family != AF_INET6) { - printf("key_check: invalid address family.\n"); - return EINVAL; - } - - /* - * prefixlen == 0 is valid because there can be a case when - * all addresses are matched. - */ - } return 0; } @@ -6450,20 +5954,18 @@ key_init() bzero((caddr_t)&key_cb, sizeof(key_cb)); - /* SAD */ -#ifdef RESTRICTED_DIR - for (i = 0; i < SADB_X_DIR_MAX; i++) - bzero(&saidxtree[i], sizeof(saidxtree[i])); -#else - bzero(&saidxtree, sizeof(saidxtree)); -#endif + for (i = 0; i < IPSEC_DIR_MAX; i++) { + LIST_INIT(&sptree[i]); + } - /* SPD */ -#ifdef RESTRICTED_DIR - for (i = 0; i < SADB_X_DIR_MAX; i++) - bzero(&sptree[i], sizeof(saidxtree[i])); -#else - bzero(&sptree, sizeof(saidxtree)); + LIST_INIT(&sahtree); + + for (i = 0; i <= SADB_SATYPE_MAX; i++) { + LIST_INIT(®tree[i]); + } + +#ifndef IPSEC_NONBLOCK_ACQUIRE + LIST_INIT(&acqtree); #endif /* system default */ @@ -6474,12 +5976,8 @@ key_init() ip6_def_policy.refcnt++; /*never reclaim this*/ #endif - /* key register */ - for (i = 0; i <= SADB_SATYPE_MAX; i++) - bzero(®tree[i], sizeof(regtree[i])); - #ifndef IPSEC_DEBUG2 - timeout((void *)key_timehandler, (void *)0, 100); + timeout((void *)key_timehandler, (void *)0, hz); #endif /*IPSEC_DEBUG2*/ /* initialize key statistics */ @@ -6491,34 +5989,30 @@ key_init() } /* + * XXX: maybe This function is called after INBOUND IPsec processing. + * * Special check for tunnel-mode packets. * We must make some checks for consistency between inner and outer IP header. * * xxx more checks to be provided */ int -key_checktunnelsanity(sa, family, src, dst) - struct secas *sa; +key_checktunnelsanity(sav, family, src, dst) + struct secasvar *sav; u_int family; caddr_t src; caddr_t dst; { /* sanity check */ - if (sa->saidx == NULL) - panic("sa->saidx == NULL in key_checktunnelsanity"); + if (sav->sah == NULL) + panic("sav->sah == NULL at key_checktunnelsanity"); - if (sa->saidx->idx.family == family - && key_bbcmp(src, (caddr_t)&sa->saidx->idx.src, sa->saidx->idx.prefs) - && key_bbcmp(dst, (caddr_t)&sa->saidx->idx.dst, sa->saidx->idx.prefd)) - return 1; + /* XXX: check inner IP header */ - return 0; + return 1; } #if 0 -#ifdef __FreeBSD__ -#define hostnamelen strlen(hostname) -#endif /* * Get FQDN for the host. @@ -6583,18 +6077,22 @@ key_getuserfqdn() /* record data transfer on SA, and update timestamps */ void -key_sa_recordxfer(sa, m) - struct secas *sa; +key_sa_recordxfer(sav, m) + struct secasvar *sav; struct mbuf *m; { - if (!sa) - panic("key_sa_recordxfer called with sa == NULL"); + if (!sav) + panic("key_sa_recordxfer called with sav == NULL"); if (!m) panic("key_sa_recordxfer called with m == NULL"); - if (!sa->lft_c) + if (!sav->lft_c) return; - sa->lft_c->sadb_lifetime_bytes += m->m_pkthdr.len; + /* + * XXX Currently, there is a difference of bytes size + * between inbound and outbound processing. + */ + sav->lft_c->sadb_lifetime_bytes += m->m_pkthdr.len; /* to check bytes lifetime is done in key_timehandler(). */ /* @@ -6602,7 +6100,7 @@ key_sa_recordxfer(sa, m) * sadb_lifetime_allocations. We increment the variable * whenever {esp,ah}_{in,out}put is called. */ - sa->lft_c->sadb_lifetime_allocations++; + sav->lft_c->sadb_lifetime_allocations++; /* XXX check for expires? */ /* @@ -6619,7 +6117,7 @@ key_sa_recordxfer(sa, m) { struct timeval tv; microtime(&tv); - sa->lft_c->sadb_lifetime_usetime = tv.tv_sec; + sav->lft_c->sadb_lifetime_usetime = tv.tv_sec; /* XXX check for expires? */ } @@ -6631,88 +6129,82 @@ void key_sa_routechange(dst) struct sockaddr *dst; { - struct secasindex *saidx; + struct secashead *sah; struct route *ro; -#ifdef RESTRICTED_DIR - u_int diridx, dir; -#endif -#ifdef RESTRICTED_DIR - for (diridx = 0; diridx < _ARRAYLEN(saorder_dir_output); diridx++) { - - dir = saorder_dir_output[diridx]; - for (saidx = (struct secasindex *)saidxtree[dir].head; - saidx != NULL; - saidx = saidx->next) { - - ro = &saidx->sa_route; - if (ro->ro_rt && dst->sa_len == ro->ro_dst.sa_len - && bcmp(dst, &ro->ro_dst, dst->sa_len) == 0) { - RTFREE(ro->ro_rt); - ro->ro_rt = (struct rtentry *)NULL; - } - } - } -#else - for (saidx = (struct secasindex *)saidxtree.head; - saidx != NULL; - saidx = saidx->next) { - - ro = &saidx->sa_route; + LIST_FOREACH(sah, &sahtree, chain) { + ro = &sah->sa_route; if (ro->ro_rt && dst->sa_len == ro->ro_dst.sa_len && bcmp(dst, &ro->ro_dst, dst->sa_len) == 0) { RTFREE(ro->ro_rt); ro->ro_rt = (struct rtentry *)NULL; } } -#endif return; } static void -key_sa_chgstate(sa, state) - struct secas *sa; - u_int state; +key_sa_chgstate(sav, state) + struct secasvar *sav; + u_int8_t state; { - if (sa == NULL) - panic("key_sa_chgstate called with sa == NULL"); + if (sav == NULL) + panic("key_sa_chgstate called with sav == NULL"); - if (sa->state == state) + if (sav->state == state) return; - key_remnode(sa); + if (__LIST_CHAINED(sav)) + LIST_REMOVE(sav, chain); - sa->state = state; - key_insnode(&sa->saidx->satree[state], NULL, sa); + sav->state = state; + LIST_INSERT_HEAD(&sav->sah->savtree[state], sav, chain); } -#ifdef __bsdi__ -#include -#include - -int *key_sysvars[] = KEYCTL_VARS; - -int -key_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; +/* returns NULL on error, m0 will be left unchanged */ +static caddr_t +key_appendmbuf(m0, len) + struct mbuf *m0; + int len; { - if (name[0] >= KEYCTL_MAXID) - return EOPNOTSUPP; - switch (name[0]) { - default: - return sysctl_int_arr(key_sysvars, name, namelen, - oldp, oldlenp, newp, newlen); - } -} -#endif /*__bsdi__*/ + caddr_t p; + struct mbuf *m; + struct mbuf *n; + + if (!m0 || (m0->m_flags & M_PKTHDR) == 0) + return NULL; /*EINVAL*/ + if (len > MCLBYTES) + return NULL; /*EINVAL*/ + + for (m = m0; m && m->m_next; m = m->m_next) + ; + if (len <= M_TRAILINGSPACE(m)) { + p = mtod(m, caddr_t) + m->m_len; + m->m_len += len; + m0->m_pkthdr.len += len; + + return p; + } + MGET(n, M_DONTWAIT, m->m_type); + if (n != NULL) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_freem(n); + n = NULL; + } + } + if (n == NULL) + return NULL; /*ENOBUFS*/ + n->m_next = NULL; + m->m_next = n; + n->m_len = len; + m0->m_pkthdr.len += len; + + return mtod(n, caddr_t); +} + -#ifdef __NetBSD__ #include #include @@ -6737,4 +6229,3 @@ key_sysctl(name, namelen, oldp, oldlenp, newp, newlen) key_sysvars[name[0]]); } } -#endif /*__NetBSD__*/ diff --git a/sys/netkey/key.h b/sys/netkey/key.h index d7cd87c3d585..1d07502f6a30 100644 --- a/sys/netkey/key.h +++ b/sys/netkey/key.h @@ -1,4 +1,4 @@ -/* $NetBSD: key.h,v 1.4 1999/07/06 12:23:23 itojun Exp $ */ +/* $NetBSD: key.h,v 1.5 2000/01/31 14:19:12 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,57 +29,49 @@ * SUCH DAMAGE. */ -/* KAME Id: key.h,v 1.1.6.1.6.1 1999/05/17 17:03:14 itojun Exp */ +/* KAME Id: key.h,v 1.8 2000/01/29 06:21:01 itojun Exp */ #ifndef _NETKEY_KEY_H_ #define _NETKEY_KEY_H_ -#ifdef __NetBSD__ -# ifdef _KERNEL -# define KERNEL -# endif -#endif - -#if defined(KERNEL) +#ifdef _KERNEL extern struct key_cb key_cb; -struct sadb_address; -struct secindex; -struct secas; +struct secpolicy; +struct secpolicyindex; +struct ipsecrequest; +struct secasvar; struct sockaddr; struct socket; -struct secexpire; struct sadb_msg; struct sadb_x_policy; -struct ipsecrequest; -extern struct secpolicy *key_allocsp __P((struct secindex *)); -#if 0 -extern int key_checkpolicy __P((struct secpolicy *)); -#endif -extern int key_checkrequest __P((struct ipsecrequest *)); -extern struct secas *key_allocsa __P((u_int, caddr_t, caddr_t, u_int, u_int)); -extern void key_freesp __P((struct secpolicy *)); -extern void key_freeso __P((struct socket *)); -extern void key_freesa __P((struct secas *)); +extern struct secpolicy *key_allocsp __P((struct secpolicyindex *spidx, + u_int dir)); +extern int key_checkrequest + __P((struct ipsecrequest *isr, struct secasindex *saidx)); +extern struct secasvar *key_allocsa __P((u_int family, caddr_t src, caddr_t dst, + u_int proto, u_int32_t spi)); +extern void key_freesp __P((struct secpolicy *sp)); +extern void key_freeso __P((struct socket *so)); +extern void key_freesav __P((struct secasvar *sav)); extern struct secpolicy *key_newsp __P((void)); -extern struct secpolicy *key_msg2sp __P((struct sadb_x_policy *)); -extern struct sadb_x_policy *key_sp2msg __P((struct secpolicy *)); - -extern int key_setsecidx __P((struct sadb_address *, struct sadb_address *, - struct secindex *, int)); -extern void key_delsecidx __P((struct secindex *)); -extern int key_setexptime __P((struct secas *)); +extern struct secpolicy *key_msg2sp __P((struct sadb_x_policy *xpl0, + size_t len, int *error)); +extern struct mbuf *key_sp2msg __P((struct secpolicy *sp)); +extern int key_ismyaddr __P((u_int family, caddr_t addr)); extern void key_timehandler __P((void)); extern void key_srandom __P((void)); -extern int key_ismyaddr __P((u_int, caddr_t)); -extern void key_freereg __P((struct socket *)); -extern int key_parse __P((struct sadb_msg **, struct socket *, int *)); +extern void key_freereg __P((struct socket *so)); +extern int key_parse __P((struct sadb_msg **msgp, struct socket *so, + int *targetp)); extern void key_init __P((void)); -extern int key_checktunnelsanity __P((struct secas *, u_int, caddr_t, caddr_t)); -extern void key_sa_recordxfer __P((struct secas *, struct mbuf *)); -extern void key_sa_routechange __P((struct sockaddr *)); +extern int key_checktunnelsanity __P((struct secasvar *sav, u_int family, + caddr_t src, caddr_t dst)); +extern void key_sa_recordxfer __P((struct secasvar *sav, struct mbuf *m)); +extern void key_sa_routechange __P((struct sockaddr *dst)); + #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_SECA); #endif /* MALLOC_DECLARE */ @@ -88,7 +80,5 @@ MALLOC_DECLARE(M_SECA); extern int key_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); #endif -#endif /* defined(KERNEL) */ - +#endif /* defined(_KERNEL) */ #endif /* _NETKEY_KEY_H_ */ - diff --git a/sys/netkey/key_debug.c b/sys/netkey/key_debug.c index b47eac694aa0..b6c8bbcf3d58 100644 --- a/sys/netkey/key_debug.c +++ b/sys/netkey/key_debug.c @@ -1,4 +1,4 @@ -/* $NetBSD: key_debug.c,v 1.7 1999/07/06 12:23:26 itojun Exp $ */ +/* $NetBSD: key_debug.c,v 1.8 2000/01/31 14:19:12 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,21 +29,15 @@ * SUCH DAMAGE. */ -/* KAME Id: key_debug.c,v 1.1.6.2.4.3 1999/07/06 12:05:13 itojun Exp */ +/* KAME Id: key_debug.c,v 1.10 2000/01/29 06:21:01 itojun Exp */ #ifdef _KERNEL -# define KERNEL -#endif - -#ifdef KERNEL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #include "opt_inet.h" #endif -#endif #include #include -#ifdef KERNEL +#ifdef _KERNEL #include #include #endif @@ -58,19 +52,13 @@ #include #include -#if !defined(KERNEL) +#ifndef _KERNEL #include #include #include -#endif /* defined(KERNEL) */ +#endif /* !_KERNEL */ -#if !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) - -#ifdef __NetBSD__ -# ifdef _KERNEL -# define KERNEL -# endif -#endif +#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) static void kdebug_sadb_prop __P((struct sadb_ext *)); static void kdebug_sadb_identity __P((struct sadb_ext *)); @@ -80,11 +68,11 @@ static void kdebug_sadb_sa __P((struct sadb_ext *)); static void kdebug_sadb_address __P((struct sadb_ext *)); static void kdebug_sadb_key __P((struct sadb_ext *)); -#ifdef KERNEL +#ifdef _KERNEL static void kdebug_secreplay __P((struct secreplay *)); #endif -#ifndef KERNEL +#ifndef _KERNEL #define panic(param) { printf(param); exit(-1); } #endif @@ -105,9 +93,11 @@ kdebug_sadb(base) printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n", base->sadb_msg_version, base->sadb_msg_type, base->sadb_msg_errno, base->sadb_msg_satype); - printf(" len=%u reserved=%u seq=%u pid=%u }\n", - base->sadb_msg_len, base->sadb_msg_reserved, - base->sadb_msg_seq, base->sadb_msg_pid); + printf(" len=%u mode=%u seq=%u pid=%u reqid=%u\n", + base->sadb_msg_len, base->sadb_msg_mode, + base->sadb_msg_seq, base->sadb_msg_pid, base->sadb_msg_reqid); + printf(" reserved1=%u reserved2=%u\n", + base->sadb_msg_reserved1, base->sadb_msg_reserved2); tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg); ext = (struct sadb_ext *)((caddr_t)base + sizeof(struct sadb_msg)); @@ -120,6 +110,10 @@ kdebug_sadb(base) printf("kdebug_sadb: invalid ext_len=0 was passed.\n"); return; } + if (ext->sadb_ext_len > tlen) { + printf("kdebug_sadb: ext_len exceeds end of buffer.\n"); + return; + } switch (ext->sadb_ext_type) { case SADB_EXT_SA: @@ -228,6 +222,7 @@ kdebug_sadb_identity(ext) { struct sadb_ident *id = (struct sadb_ident *)ext; int len; + union sadb_x_ident_id *aid; /* sanity check */ if (ext == NULL) @@ -236,25 +231,40 @@ kdebug_sadb_identity(ext) len = PFKEY_UNUNIT64(id->sadb_ident_len) - sizeof(*id); printf("sadb_ident_%s{", id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst"); - printf(" type=%d id=%lu", - id->sadb_ident_type, (u_long)id->sadb_ident_id); - if (len) { -#ifdef KERNEL - ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/ + switch (id->sadb_ident_type) { + case SADB_X_IDENTTYPE_ADDR: + aid = (union sadb_x_ident_id *)&id->sadb_ident_id; + + printf(" type=%d prefix=%u ul_proto=%u\n", + id->sadb_ident_type, + aid->sadb_x_ident_id_addr.prefix, + aid->sadb_x_ident_id_addr.ul_proto); + kdebug_sockaddr((struct sockaddr *)(id + 1)); + break; + + default: + printf(" type=%d id=%lu", + id->sadb_ident_type, (u_long)id->sadb_ident_id); + if (len) { +#ifdef _KERNEL + ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/ #else - char *p, *ep; - printf("\n str=\""); - p = (char *)(id + 1); - ep = p + len; - for (/*nothing*/; *p && p < ep; p++) { - if (isprint(*p)) - printf("%c", *p & 0xff); - else - printf("\\%03o", *p & 0xff); - } + char *p, *ep; + printf("\n str=\""); + p = (char *)(id + 1); + ep = p + len; + for (/*nothing*/; *p && p < ep; p++) { + if (isprint(*p)) + printf("%c", *p & 0xff); + else + printf("\\%03o", *p & 0xff); + } #endif - printf("\""); + printf("\""); + } + break; } + printf(" }\n"); return; @@ -356,7 +366,7 @@ kdebug_sadb_key(ext) if (ext == NULL) panic("kdebug_sadb_key: NULL pointer was passed.\n"); - printf("sadb_key{ bits=%u reserved=%u }\n", + printf("sadb_key{ bits=%u reserved=%u\n", key->sadb_key_bits, key->sadb_key_reserved); printf(" key="); @@ -379,72 +389,66 @@ kdebug_sadb_x_policy(ext) struct sadb_ext *ext; { struct sadb_x_policy *xpl = (struct sadb_x_policy *)ext; + struct sockaddr *addr; /* sanity check */ if (ext == NULL) panic("kdebug_sadb_x_policy: NULL pointer was passed.\n"); - printf("sadb_x_policy{ type=%u reserved=%x }\n", - xpl->sadb_x_policy_type, xpl->sadb_x_policy_reserved); + printf("sadb_x_policy{ type=%u dir=%u reserved=%x }\n", + xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir, + xpl->sadb_x_policy_reserved); if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) { int tlen; struct sadb_x_ipsecrequest *xisr; - int xxx_len; /* for sanity check */ tlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl); - xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl - + sizeof(*xpl)); + xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); while (tlen > 0) { - printf(" { len=%u proto=%u mode=%u level=%u", + printf(" { len=%u proto=%u mode=%u level=%u reqid=%u\n", xisr->sadb_x_ipsecrequest_len, xisr->sadb_x_ipsecrequest_proto, xisr->sadb_x_ipsecrequest_mode, - xisr->sadb_x_ipsecrequest_level); + xisr->sadb_x_ipsecrequest_level, + xisr->sadb_x_ipsecrequest_reqid); - xxx_len = sizeof(*xisr); - - /* tunnel mode ? */ - if (xisr->sadb_x_ipsecrequest_mode ==IPSEC_MODE_TUNNEL){ - struct sockaddr *addr - = (struct sockaddr *)((caddr_t)xisr - + sizeof(*xisr)); - - printf("\n"); - xxx_len += PFKEY_ALIGN8(addr->sa_len); + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + addr = (struct sockaddr *)(xisr + 1); kdebug_sockaddr(addr); - } else - printf(" }\n"); + addr = (struct sockaddr *)((caddr_t)addr + + addr->sa_len); + kdebug_sockaddr(addr); + } - /* sanity check */ - if (xisr->sadb_x_ipsecrequest_len != xxx_len) { - printf("kdebug_sadb_x_policy: " - "Invalid request length, " - "reqlen:%d real:%d\n", - xisr->sadb_x_ipsecrequest_len, - xxx_len); + printf(" }\n"); + + /* prevent infinite loop */ + if (xisr->sadb_x_ipsecrequest_len <= 0) { + printf("kdebug_sadb_x_policy: wrong policy struct.\n"); + return; + } + /* prevent overflow */ + if (xisr->sadb_x_ipsecrequest_len > tlen) { + printf("invalid ipsec policy length\n"); return; } tlen -= xisr->sadb_x_ipsecrequest_len; - /* sanity check */ - if (tlen < 0) { - printf("kdebug_sadb_x_policy: " - "becoming tlen < 0.\n"); - return; - } - xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + xisr->sadb_x_ipsecrequest_len); } + + if (tlen != 0) + panic("kdebug_sadb_x_policy: wrong policy struct.\n"); } return; } -#ifdef KERNEL +#ifdef _KERNEL /* %%%: about SPD and SAD */ void kdebug_secpolicy(sp) @@ -457,7 +461,7 @@ kdebug_secpolicy(sp) printf("secpolicy{ refcnt=%u state=%u policy=%u\n", sp->refcnt, sp->state, sp->policy); - kdebug_secindex(&sp->idx); + kdebug_secpolicyindex(&sp->spidx); switch (sp->policy) { case IPSEC_POLICY_DISCARD: @@ -471,22 +475,11 @@ kdebug_secpolicy(sp) struct ipsecrequest *isr; for (isr = sp->req; isr != NULL; isr = isr->next) { - printf(" proto=%u mode=%u level=%u\n", - isr->proto, isr->mode, isr->level); + printf(" level=%u\n", isr->level); + kdebug_secasindex(&isr->saidx); - if (isr->mode == IPSEC_MODE_TUNNEL) { - /* sanity check */ - if (isr->proxy == NULL) { - printf("kdebug_secpolicy: " - "Specified tunnel mode, " - "but proxy points to NULL.\n"); - continue; - } - kdebug_sockaddr(isr->proxy); - } - - if (isr->sa != NULL) - kdebug_secas(isr->sa); + if (isr->sav != NULL) + kdebug_secasv(isr->sav); } printf(" }\n"); } @@ -507,65 +500,85 @@ kdebug_secpolicy(sp) } void -kdebug_secindex(idx) - struct secindex *idx; +kdebug_secpolicyindex(spidx) + struct secpolicyindex *spidx; { /* sanity check */ - if (idx == NULL) - panic("kdebug_secindex: NULL pointer was passed.\n"); + if (spidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); - printf("secindex{ family=%u prefs=%u prefd=%d\n", - idx->family, idx->prefs, idx->prefd); + printf("secpolicyindex{ dir=%u prefs=%u prefd=%u ul_proto=%u\n", + spidx->dir, spidx->prefs, spidx->prefd, spidx->ul_proto); - ipsec_hexdump((caddr_t)&idx->src, _INALENBYAF(idx->family)); + ipsec_hexdump((caddr_t)&spidx->src, + ((struct sockaddr *)&spidx->src)->sa_len); printf("\n"); - ipsec_hexdump((caddr_t)&idx->dst, _INALENBYAF(idx->family)); - printf("\n"); - - printf(" proto=%u ports=%u portd=%d }\n", - idx->proto, ntohs(idx->ports), ntohs(idx->portd)); + ipsec_hexdump((caddr_t)&spidx->dst, + ((struct sockaddr *)&spidx->dst)->sa_len); + printf("}\n"); return; } void -kdebug_secas(sa) - struct secas *sa; +kdebug_secasindex(saidx) + struct secasindex *saidx; { /* sanity check */ - if (sa == NULL) - panic("kdebug_secas: NULL pointer was passed.\n"); + if (saidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secasindex{ mode=%u proto=%u\n", + saidx->mode, saidx->proto); + + ipsec_hexdump((caddr_t)&saidx->src, + ((struct sockaddr *)&saidx->src)->sa_len); + printf("\n"); + ipsec_hexdump((caddr_t)&saidx->dst, + ((struct sockaddr *)&saidx->dst)->sa_len); + printf("\n"); + + return; +} + +void +kdebug_secasv(sav) + struct secasvar *sav; +{ + /* sanity check */ + if (sav == NULL) + panic("kdebug_secasv: NULL pointer was passed.\n"); printf("secas{"); - kdebug_secindex(&sa->saidx->idx); + kdebug_secasindex(&sav->sah->saidx); - printf(" refcnt=%u state=%u type=%u auth=%u enc=%u\n", - sa->refcnt, sa->state, sa->type, sa->alg_auth, sa->alg_enc); - printf(" spi=%lu flags=%u\n", (unsigned long) ntohl(sa->spi), - sa->flags); + printf(" refcnt=%u state=%u auth=%u enc=%u\n", + sav->refcnt, sav->state, sav->alg_auth, sav->alg_enc); + printf(" spi=%u flags=%u\n", + (u_int32_t)ntohl(sav->spi), sav->flags); - if (sa->key_auth != NULL) - kdebug_sadb_key((struct sadb_ext *)sa->key_auth); - if (sa->key_enc != NULL) - kdebug_sadb_key((struct sadb_ext *)sa->key_enc); - if (sa->iv != NULL) { - ipsec_hexdump(sa->iv, sa->ivlen ? sa->ivlen : 8); + if (sav->key_auth != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_auth); + if (sav->key_enc != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_enc); + if (sav->iv != NULL) { + printf(" iv="); + ipsec_hexdump(sav->iv, sav->ivlen ? sav->ivlen : 8); printf("\n"); } - if (sa->proxy != NULL) { - kdebug_sockaddr(sa->proxy); - printf("\n"); - } - if (sa->replay != NULL) - kdebug_secreplay(sa->replay); - if (sa->lft_c != NULL) - kdebug_sadb_lifetime((struct sadb_ext *)sa->lft_c); - if (sa->lft_h != NULL) - kdebug_sadb_lifetime((struct sadb_ext *)sa->lft_h); - if (sa->lft_s != NULL) - kdebug_sadb_lifetime((struct sadb_ext *)sa->lft_s); + if (sav->replay != NULL) + kdebug_secreplay(sav->replay); + if (sav->lft_c != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_c); + if (sav->lft_h != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_h); + if (sav->lft_s != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_s); + +#if notyet /* XXX: misc[123] ? */ +#endif return; } @@ -617,14 +630,6 @@ kdebug_mbufhdr(m) m->m_pkthdr.len, m->m_pkthdr.rcvif); } -#ifdef __FreeBSD__ - if (m->m_flags & M_EXT) { - printf(" m_ext{ ext_buf:%p ext_free:%p " - "ext_size:%u ext_ref:%p }\n", - m->m_ext.ext_buf, m->m_ext.ext_free, - m->m_ext.ext_size, m->m_ext.ext_ref); - } -#endif return; } @@ -651,7 +656,7 @@ kdebug_mbuf(m0) return; } -#endif /* KERNEL */ +#endif /* _KERNEL */ void kdebug_sockaddr(addr) @@ -680,7 +685,7 @@ kdebug_sockaddr(addr) return; } -#endif /* !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) */ +#endif /* !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) */ void ipsec_bindump(buf, len) diff --git a/sys/netkey/key_debug.h b/sys/netkey/key_debug.h index 7405a9256188..aadcb20dd907 100644 --- a/sys/netkey/key_debug.h +++ b/sys/netkey/key_debug.h @@ -1,4 +1,4 @@ -/* $NetBSD: key_debug.h,v 1.4 1999/07/06 12:23:26 itojun Exp $ */ +/* $NetBSD: key_debug.h,v 1.5 2000/01/31 14:19:12 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,18 +29,12 @@ * SUCH DAMAGE. */ -/* KAME Id: key_debug.h,v 1.1.6.2.6.1 1999/05/17 17:03:16 itojun Exp */ +/* KAME Id: key_debug.h,v 1.3 2000/01/29 06:21:02 itojun Exp */ #ifndef _NETKEY_KEY_DEBUG_H_ #define _NETKEY_KEY_DEBUG_H_ -#ifdef __NetBSD__ -# ifdef _KERNEL -# define KERNEL -# endif -#endif - -#if !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) +#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) /* debug flags */ #define KEYDEBUG_STAMP 0x00000001 /* path */ @@ -63,27 +57,29 @@ #define KEYDEBUG(lev,arg) if ((key_debug_level & (lev)) == (lev)) { arg; } -#ifdef KERNEL +#ifdef _KERNEL extern u_int32_t key_debug_level; -#endif /*KERNEL*/ +#endif /*_KERNEL*/ struct sadb_msg; struct sadb_ext; extern void kdebug_sadb __P((struct sadb_msg *)); extern void kdebug_sadb_x_policy __P((struct sadb_ext *)); -#ifdef KERNEL +#ifdef _KERNEL struct secpolicy; -struct secindex; -struct secas; +struct secpolicyindex; +struct secasindex; +struct secasvar; struct secreplay; struct mbuf; -extern void kdebug_secindex __P((struct secindex *)); extern void kdebug_secpolicy __P((struct secpolicy *)); -extern void kdebug_secas __P((struct secas *)); +extern void kdebug_secpolicyindex __P((struct secpolicyindex *)); +extern void kdebug_secasindex __P((struct secasindex *)); +extern void kdebug_secasv __P((struct secasvar *)); extern void kdebug_mbufhdr __P((struct mbuf *)); extern void kdebug_mbuf __P((struct mbuf *)); -#endif /*KERNEL*/ +#endif /*_KERNEL*/ struct sockaddr; extern void kdebug_sockaddr __P((struct sockaddr *)); @@ -92,7 +88,7 @@ extern void kdebug_sockaddr __P((struct sockaddr *)); #define KEYDEBUG(lev,arg) -#endif /*!defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG))*/ +#endif /*!defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG))*/ extern void ipsec_hexdump __P((caddr_t, int)); extern void ipsec_bindump __P((caddr_t, int)); diff --git a/sys/netkey/key_var.h b/sys/netkey/key_var.h index d2fb495e9e02..fa59ca292021 100644 --- a/sys/netkey/key_var.h +++ b/sys/netkey/key_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: key_var.h,v 1.6 1999/08/24 00:46:13 itojun Exp $ */ +/* $NetBSD: key_var.h,v 1.7 2000/01/31 14:19:12 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -94,7 +94,7 @@ #define _INADDR(in) ((struct sockaddr_in *)(in)) -#if defined(INET6) +#ifdef INET6 #define _IN6ADDR(in6) ((struct sockaddr_in6 *)(in6)) #define _SALENBYAF(family) \ (((family) == AF_INET) ? \ diff --git a/sys/netkey/keydb.c b/sys/netkey/keydb.c new file mode 100644 index 000000000000..e8ddac2f712c --- /dev/null +++ b/sys/netkey/keydb.c @@ -0,0 +1,215 @@ +/* $NetBSD: keydb.c,v 1.1 2000/01/31 14:19:13 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* KAME Id: keydb.c,v 1.58 2000/01/17 14:11:16 itojun Exp */ + +#include "opt_inet.h" +#include "opt_ipsec.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +static void keydb_delsecasvar __P((struct secasvar *)); + +/* + * secpolicy management + */ +struct secpolicy * +keydb_newsecpolicy() +{ + struct secpolicy *p; + + p = (struct secpolicy *)malloc(sizeof(*p), M_SECA, M_NOWAIT); + if (!p) + return p; + bzero(p, sizeof(*p)); + return p; +} + +void +keydb_delsecpolicy(p) + struct secpolicy *p; +{ + + free(p, M_SECA); +} + +/* + * secashead management + */ +struct secashead * +keydb_newsecashead() +{ + struct secashead *p; + int i; + + p = (struct secashead *)malloc(sizeof(*p), M_SECA, M_NOWAIT); + if (!p) + return p; + bzero(p, sizeof(*p)); + for (i = 0; i < sizeof(p->savtree)/sizeof(p->savtree[0]); i++) + LIST_INIT(&p->savtree[i]); + return p; +} + +void +keydb_delsecashead(p) + struct secashead *p; +{ + + free(p, M_SECA); +} + +/* + * secasvar management (reference counted) + */ +struct secasvar * +keydb_newsecasvar() +{ + struct secasvar *p; + + p = (struct secasvar *)malloc(sizeof(*p), M_SECA, M_NOWAIT); + if (!p) + return p; + bzero(p, sizeof(*p)); + p->refcnt = 1; + return p; +} + +void +keydb_refsecasvar(p) + struct secasvar *p; +{ + int s; + + s = splsoftnet(); + p->refcnt++; + splx(s); +} + +void +keydb_freesecasvar(p) + struct secasvar *p; +{ + int s; + + s = splsoftnet(); + p->refcnt--; + if (p->refcnt == 0) + keydb_delsecasvar(p); + splx(s); +} + +static void +keydb_delsecasvar(p) + struct secasvar *p; +{ + + if (p->refcnt) + panic("keydb_delsecasvar called with refcnt != 0"); + + free(p, M_SECA); +} + +/* + * secreplay management + */ +struct secreplay * +keydb_newsecreplay(wsize) + size_t wsize; +{ + struct secreplay *p; + + p = (struct secreplay *)malloc(sizeof(*p), M_SECA, M_NOWAIT); + if (!p) + return p; + + bzero(p, sizeof(*p)); + if (wsize != 0) { + p->bitmap = (caddr_t)malloc(wsize, M_SECA, M_NOWAIT); + if (!p->bitmap) { + free(p, M_SECA); + return NULL; + } + bzero(p->bitmap, wsize); + } + p->wsize = wsize; + return p; +} + +void +keydb_delsecreplay(p) + struct secreplay *p; +{ + + if (p->bitmap) + free(p->bitmap, M_SECA); + free(p, M_SECA); +} + +/* + * secreg management + */ +struct secreg * +keydb_newsecreg() +{ + struct secreg *p; + + p = (struct secreg *)malloc(sizeof(*p), M_SECA, M_NOWAIT); + if (p) + bzero(p, sizeof(*p)); + return p; +} + +void +keydb_delsecreg(p) + struct secreg *p; +{ + + free(p, M_SECA); +} diff --git a/sys/netkey/keydb.h b/sys/netkey/keydb.h index 586d4353dbf3..376b48ee3f78 100644 --- a/sys/netkey/keydb.h +++ b/sys/netkey/keydb.h @@ -1,4 +1,4 @@ -/* $NetBSD: keydb.h,v 1.3 1999/07/03 21:32:48 thorpej Exp $ */ +/* $NetBSD: keydb.h,v 1.4 2000/01/31 14:19:13 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -32,119 +32,74 @@ #ifndef _NETKEY_KEYDB_H_ #define _NETKEY_KEYDB_H_ -#ifdef __NetBSD__ -# ifdef _KERNEL -# define KERNEL -# endif -#endif - -#ifdef KERNEL +#ifdef _KERNEL #include -/* Must include ipsec.h and keyv2.h before in its use. */ - -/* management for the tree and nodes. */ -struct keytree { - struct keynode *head; - struct keynode *tail; - int len; +/* Security Assocciation Index */ +/* NOTE: Ensure to be same address family */ +struct secasindex { + struct sockaddr_storage src; /* srouce address for SA */ + struct sockaddr_storage dst; /* destination address for SA */ + u_int16_t proto; /* IPPROTO_ESP or IPPROTO_AH */ + u_int8_t mode; /* mode of protocol, see ipsec.h */ + u_int32_t reqid; /* reqid id who owned this SA */ + /* see IPSEC_MANUAL_REQID_MAX. */ }; -struct keynode { - struct keynode *next; - struct keynode *prev; - struct keytree *back; /* pointer to the keytree */ -}; - -/* index structure for SPD and SAD */ -/* NOTE: All field are network byte order. */ -struct secindex { - u_int8_t family; /* AF_INET or AF_INET6 */ - u_int8_t prefs; /* preference for srouce address in bits */ - u_int8_t prefd; /* preference for destination address in bits */ - u_int8_t proto; /* upper layer Protocol */ - u_int16_t ports; /* source port */ - u_int16_t portd; /* destination port */ - union { -#if 0 /* #include dependency... */ - struct in_addr src4; - struct in6_addr src6; -#endif - u_int8_t srcany[16]; /*guarantee minimum size*/ - } src; /* buffer for source address */ - union { -#if 0 /* #include dependency... */ - struct in_addr dst4; - struct in6_addr dst6; -#endif - u_int8_t dstany[16]; /*guarantee minimum size*/ - } dst; /* buffer for destination address */ -}; - -/* direction of SA */ -#define SADB_X_DIR_UNKNOWN 0 /* initial */ -#define SADB_X_DIR_INBOUND 1 -#define SADB_X_DIR_OUTBOUND 2 -#define SADB_X_DIR_BIDIRECT 3 /* including loopback */ -#define SADB_X_DIR_MAX 4 -#define SADB_X_DIR_INVALID 4 - /* - * Since X_DIR_INVALID is equal to SADB_X_DIR_MAX, - * it can be used just as flag. The other are too - * used for loop counter. - */ - /* Security Association Data Base */ -struct secasindex { - struct secasindex *next; - struct secasindex *prev; - struct keytree *saidxt; /* back pointer to */ - /* the top of SA index tree */ +struct secashead { + LIST_ENTRY(secashead) chain; - struct secindex idx; /* security index */ + struct secasindex saidx; - struct keytree satree[SADB_SASTATE_MAX+1]; + struct sadb_ident *idents; /* source identity */ + struct sadb_ident *identd; /* destination identity */ + /* XXX I don't know how to use them. */ + + u_int8_t state; /* MATURE or DEAD. */ + LIST_HEAD(_satree, secasvar) savtree[SADB_SASTATE_MAX+1]; /* SA chain */ + /* The first of this list is newer SA */ - struct route sa_route; /* XXX */ + struct route sa_route; /* route cache */ }; /* Security Association */ -struct secas { - struct secas *next; - struct secas *prev; - struct keytree *sat; /* back pointer to the top of SA tree */ +struct secasvar { + LIST_ENTRY(secasvar) chain; int refcnt; /* reference count */ u_int8_t state; /* Status of this Association */ - u_int8_t type; /* Type of this association: protocol */ + u_int8_t alg_auth; /* Authentication Algorithm Identifier*/ u_int8_t alg_enc; /* Cipher Algorithm Identifier */ u_int32_t spi; /* SPI Value, network byte order */ u_int32_t flags; /* holder for SADB_KEY_FLAGS */ + struct sadb_key *key_auth; /* Key for Authentication */ /* length has been shifted up to 3. */ struct sadb_key *key_enc; /* Key for Encryption */ /* length has been shifted up to 3. */ - struct sockaddr *proxy; /* Proxy IP address for Destination */ + caddr_t iv; /* Initilization Vector */ + u_int ivlen; /* length of IV */ +#if 0 + caddr_t misc1; + caddr_t misc2; + caddr_t misc3; +#endif + struct secreplay *replay; /* replay prevention */ u_int32_t tick; /* for lifetime */ + struct sadb_lifetime *lft_c; /* CURRENT lifetime, it's constant. */ struct sadb_lifetime *lft_h; /* HARD lifetime */ struct sadb_lifetime *lft_s; /* SOFT lifetime */ - /* sadb_lifetime_len is in 32 bits. */ - - caddr_t iv; /* Initilization Vector */ - u_int ivlen; /* XXX: quick hack */ - caddr_t misc1; /* the use for example DES's setkey. */ - caddr_t misc2; - caddr_t misc3; u_int32_t seq; /* sequence number */ - u_int32_t pid; /* pid */ + pid_t pid; /* message's pid */ - struct secasindex *saidx; /* back pointer to the secasindex */ + struct secashead *sah; /* back pointer to the secashead */ }; /* replay prevention */ @@ -154,31 +109,22 @@ struct secreplay { u_int32_t seq; /* used by sender */ u_int32_t lastseq; /* used by receiver */ caddr_t bitmap; /* used by receiver */ + int overflow; /* overflow flag */ }; /* socket table due to send PF_KEY messages. */ struct secreg { - struct secreg *next; - struct secreg *prev; - struct keytree *regt; /* back pointer to the top of secreg tree */ + LIST_ENTRY(secreg) chain; struct socket *so; }; -#ifndef IPSEC_BLOCK_ACQUIRE +#ifndef IPSEC_NONBLOCK_ACQUIRE /* acquiring list table. */ struct secacq { - struct secacq *next; - struct secacq *prev; - struct keytree *acqt; /* back pointer to the top of secacq tree */ + LIST_ENTRY(secacq) chain; -#if 1 - struct secindex idx; /* security index */ - u_int8_t proto; /* Type of this association: IPsec protocol */ - u_int8_t proxy[16]; /* buffer for proxy address */ -#else - u_int8_t hash[16]; -#endif + struct secasindex saidx; u_int32_t seq; /* sequence number */ u_int32_t tick; /* for lifetime */ @@ -196,6 +142,23 @@ struct key_cb { int any_count; }; -#endif /* KERNEL */ +/* secpolicy */ +extern struct secpolicy *keydb_newsecpolicy __P((void)); +extern void keydb_delsecpolicy __P((struct secpolicy *)); +/* secashead */ +extern struct secashead *keydb_newsecashead __P((void)); +extern void keydb_delsecashead __P((struct secashead *)); +/* secasvar */ +extern struct secasvar *keydb_newsecasvar __P((void)); +extern void keydb_refsecasvar __P((struct secasvar *)); +extern void keydb_freesecasvar __P((struct secasvar *)); +/* secreplay */ +extern struct secreplay *keydb_newsecreplay __P((size_t)); +extern void keydb_delsecreplay __P((struct secreplay *)); +/* secreg */ +extern struct secreg *keydb_newsecreg __P((void)); +extern void keydb_delsecreg __P((struct secreg *)); + +#endif /* _KERNEL */ #endif /* _NETKEY_KEYDB_H_ */ diff --git a/sys/netkey/keysock.c b/sys/netkey/keysock.c index 10ba7376207f..fd246d2d591f 100644 --- a/sys/netkey/keysock.c +++ b/sys/netkey/keysock.c @@ -1,4 +1,4 @@ -/* $NetBSD: keysock.c,v 1.6 1999/07/31 18:41:18 itojun Exp $ */ +/* $NetBSD: keysock.c,v 1.7 2000/01/31 14:19:13 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,41 +29,24 @@ * SUCH DAMAGE. */ -/* KAME Id: keysock.c,v 1.1.6.4.2.2 1999/07/04 02:06:39 itojun Exp */ +/* KAME Id: keysock.c,v 1.10 2000/01/29 06:21:02 itojun Exp */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 #include "opt_inet.h" -#endif /* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */ -#ifdef __NetBSD__ -# ifdef _KERNEL -# define KERNEL -# endif -#endif - #include #include #include #include -#ifdef __FreeBSD__ -#include -#endif #include #include #include #include #include #include -#ifdef __NetBSD__ #include #include -#endif - -#ifdef __FreeBSD__ -#include -#endif #include #include @@ -82,56 +65,26 @@ struct sockproto key_proto = { PF_KEY, PF_KEY_V2 }; static int key_sendup0 __P((struct rawcb *, struct mbuf *, int)); -#if 1 -#define KMALLOC(p, t, n) \ - ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT)) -#define KFREE(p) \ - free((caddr_t)(p), M_SECA); -#else -#define KMALLOC(p, t, n) \ - do { \ - ((p) = (t)malloc((unsigned long)(n), M_SECA, M_NOWAIT));\ - printf("%s %d: %p <- KMALLOC(%s, %d)\n", \ - __FILE__, __LINE__, (p), #t, n); \ - } while (0) - -#define KFREE(p) \ - do { \ - printf("%s %d: %p -> KFREE()\n", __FILE__, __LINE__, (p));\ - free((caddr_t)(p), M_SECA); \ - } while (0) -#endif +struct pfkeystat pfkeystat; /* * key_usrreq() * derived from net/rtsock.c:route_usrreq() */ -#ifndef __NetBSD__ -int -key_usrreq(so, req, m, nam, control) - register struct socket *so; - int req; - struct mbuf *m, *nam, *control; -#else int key_usrreq(so, req, m, nam, control, p) register struct socket *so; int req; struct mbuf *m, *nam, *control; struct proc *p; -#endif /*__NetBSD__*/ { register int error = 0; register struct keycb *kp = (struct keycb *)sotorawcb(so); int s; -#ifdef __NetBSD__ s = splsoftnet(); -#else - s = splnet(); -#endif if (req == PRU_ATTACH) { - MALLOC(kp, struct keycb *, sizeof(*kp), M_PCB, M_WAITOK); + kp = (struct keycb *)malloc(sizeof(*kp), M_PCB, M_WAITOK); so->so_pcb = (caddr_t)kp; if (so->so_pcb) bzero(so->so_pcb, sizeof(*kp)); @@ -145,17 +98,16 @@ key_usrreq(so, req, m, nam, control, p) key_freereg(so); } -#ifndef __NetBSD__ - error = raw_usrreq(so, req, m, nam, control); -#else error = raw_usrreq(so, req, m, nam, control, p); -#endif m = control = NULL; /* reclaimed in raw_usrreq */ kp = (struct keycb *)sotorawcb(so); if (req == PRU_ATTACH && kp) { int af = kp->kp_raw.rcb_proto.sp_protocol; if (error) { +#ifdef IPSEC_DEBUG printf("key_usrreq: key_usrreq results %d\n", error); +#endif + pfkeystat.sockerr++; free((caddr_t)kp, M_PCB); so->so_pcb = (caddr_t) 0; splx(s); @@ -167,43 +119,8 @@ key_usrreq(so, req, m, nam, control, p) if (af == PF_KEY) /* XXX: AF_KEY */ key_cb.key_count++; key_cb.any_count++; -#ifndef __bsdi__ kp->kp_raw.rcb_laddr = &key_src; kp->kp_raw.rcb_faddr = &key_dst; -#else - /* - * XXX rcb_faddr must be dynamically allocated, otherwise - * raw_disconnect() will be angry. - */ - { - struct mbuf *m, *n; - MGET(m, M_WAITOK, MT_DATA); - if (!m) { - error = ENOBUFS; - printf("key_usrreq: key_usrreq results %d\n", error); - free((caddr_t)kp, M_PCB); - so->so_pcb = (caddr_t) 0; - splx(s); - return(error); - } - MGET(n, M_WAITOK, MT_DATA); - if (!n) { - error = ENOBUFS; - m_freem(m); - printf("key_usrreq: key_usrreq results %d\n", error); - free((caddr_t)kp, M_PCB); - so->so_pcb = (caddr_t) 0; - splx(s); - return(error); - } - m->m_len = sizeof(key_src); - kp->kp_raw.rcb_laddr = mtod(m, struct sockaddr *); - bcopy(&key_src, kp->kp_raw.rcb_laddr, sizeof(key_src)); - n->m_len = sizeof(key_dst); - kp->kp_raw.rcb_faddr = mtod(n, struct sockaddr *); - bcopy(&key_dst, kp->kp_raw.rcb_faddr, sizeof(key_dst)); - } -#endif soisconnected(so); so->so_options |= SO_USELOOPBACK; } @@ -237,24 +154,44 @@ key_output(m, va_alist) if (m == 0) panic("key_output: NULL pointer was passed.\n"); - if (m->m_len < sizeof(long) - && (m = m_pullup(m, 8)) == 0) { - printf("key_output: can't pullup mbuf\n"); - error = ENOBUFS; + pfkeystat.out_total++; + pfkeystat.out_bytes += m->m_pkthdr.len; + + len = m->m_pkthdr.len; + if (len < sizeof(struct sadb_msg)) { +#ifdef IPSEC_DEBUG + printf("key_output: Invalid message length.\n"); +#endif + pfkeystat.out_tooshort++; + error = EINVAL; goto end; } + if (m->m_len < sizeof(struct sadb_msg)) { + if ((m = m_pullup(m, sizeof(struct sadb_msg))) == 0) { +#ifdef IPSEC_DEBUG + printf("key_output: can't pullup mbuf\n"); +#endif + pfkeystat.out_nomem++; + error = ENOBUFS; + goto end; + } + } + if ((m->m_flags & M_PKTHDR) == 0) panic("key_output: not M_PKTHDR ??"); -#if defined(IPSEC_DEBUG) +#ifdef IPSEC_DEBUG KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m)); #endif /* defined(IPSEC_DEBUG) */ - len = m->m_pkthdr.len; - if (len < sizeof(struct sadb_msg) - || len != PFKEY_UNUNIT64(mtod(m, struct sadb_msg *)->sadb_msg_len)) { + msg = mtod(m, struct sadb_msg *); + pfkeystat.out_msgtype[msg->sadb_msg_type]++; + if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) { +#ifdef IPSEC_DEBUG printf("key_output: Invalid message length.\n"); +#endif + pfkeystat.out_invlen++; error = EINVAL; goto end; } @@ -263,23 +200,23 @@ key_output(m, va_alist) * allocate memory for sadb_msg, and copy to sadb_msg from mbuf * XXX: To be processed directly without a copy. */ - KMALLOC(msg, struct sadb_msg *, len); - if (msg == 0) { + msg = (struct sadb_msg *)malloc(len, M_SECA, M_NOWAIT); + if (msg == NULL) { +#ifdef IPSEC_DEBUG printf("key_output: No more memory.\n"); +#endif error = ENOBUFS; + pfkeystat.out_nomem++; goto end; /* or do panic ? */ } m_copydata(m, 0, len, (caddr_t)msg); /*XXX giant lock*/ -#ifdef __NetBSD__ s = splsoftnet(); -#else - s = splnet(); -#endif if ((len = key_parse(&msg, so, &target)) == 0) { /* discard. i.e. no need to reply. */ + /* msg has been freed at key_parse() */ error = 0; splx(s); goto end; @@ -288,7 +225,7 @@ key_output(m, va_alist) /* send up message to the socket */ error = key_sendup(so, msg, len, target); splx(s); - KFREE(msg); + free(msg, M_SECA); end: m_freem(m); return (error); @@ -310,7 +247,10 @@ key_sendup0(rp, m, promisc) if (m && m->m_len < sizeof(struct sadb_msg)) m = m_pullup(m, sizeof(struct sadb_msg)); if (!m) { +#ifdef IPSEC_DEBUG printf("key_sendup0: cannot pullup\n"); +#endif + pfkeystat.in_nomem++; m_freem(m); return ENOBUFS; } @@ -322,11 +262,16 @@ key_sendup0(rp, m, promisc) pmsg->sadb_msg_type = SADB_X_PROMISC; pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); /* pid and seq? */ + + pfkeystat.in_msgtype[pmsg->sadb_msg_type]++; } if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src, m, NULL)) { +#ifdef IPSEC_DEBUG printf("key_sendup0: sbappendaddr failed\n"); +#endif + pfkeystat.in_nomem++; m_freem(m); return ENOBUFS; } @@ -334,6 +279,7 @@ key_sendup0(rp, m, promisc) return 0; } +/* XXX this interface should be obsoleted. */ int key_sendup(so, msg, len, target) struct socket *so; @@ -342,10 +288,6 @@ key_sendup(so, msg, len, target) int target; /*target of the resulting message*/ { struct mbuf *m, *n, *mprev; - struct keycb *kp; - int sendup; - struct rawcb *rp; - int error; int tlen; /* sanity check */ @@ -356,6 +298,14 @@ key_sendup(so, msg, len, target) printf("key_sendup: \n"); kdebug_sadb(msg)); + /* + * we increment statistics here, just in case we have ENOBUFS + * in this function. + */ + pfkeystat.in_total++; + pfkeystat.in_bytes += len; + pfkeystat.in_msgtype[msg->sadb_msg_type]++; + /* * Get mbuf chain whenever possible (not clusters), * to save socket buffer. We'll be generating many SADB_ACQUIRE @@ -375,13 +325,16 @@ key_sendup(so, msg, len, target) MGET(n, M_DONTWAIT, MT_DATA); n->m_len = MLEN; } - if (!n) + if (!n) { + pfkeystat.in_nomem++; return ENOBUFS; - if (tlen > MCLBYTES) { /*XXX better threshold? */ + } + if (tlen >= MCLBYTES) { /*XXX better threshold? */ MCLGET(n, M_DONTWAIT); if ((n->m_flags & M_EXT) == 0) { m_free(n); m_freem(m); + pfkeystat.in_nomem++; return ENOBUFS; } n->m_len = MCLBYTES; @@ -403,11 +356,49 @@ key_sendup(so, msg, len, target) m->m_pkthdr.rcvif = NULL; m_copyback(m, 0, len, (caddr_t)msg); -#ifndef __NetBSD__ - for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) + /* avoid duplicated statistics */ + pfkeystat.in_total--; + pfkeystat.in_bytes -= len; + pfkeystat.in_msgtype[msg->sadb_msg_type]--; + + return key_sendup_mbuf(so, m, target); +} + +int +key_sendup_mbuf(so, m, target) + struct socket *so; + struct mbuf *m; + int target; +{ + struct mbuf *n; + struct keycb *kp; + int sendup; + struct rawcb *rp; + int error; + + if (so == NULL || m == NULL) + panic("key_sendup_mbuf: NULL pointer was passed.\n"); + + pfkeystat.in_total++; + pfkeystat.in_bytes += m->m_pkthdr.len; + if (m->m_len < sizeof(struct sadb_msg)) { +#if 1 + m = m_pullup(m, sizeof(struct sadb_msg)); + if (m == NULL) { + pfkeystat.in_nomem++; + return ENOBUFS; + } #else - for (rp = rawcb.lh_first; rp; rp = rp->rcb_list.le_next) + /* don't bother pulling it up just for stats */ #endif + } + if (m->m_len >= sizeof(struct sadb_msg)) { + struct sadb_msg *msg; + msg = mtod(m, struct sadb_msg *); + pfkeystat.in_msgtype[msg->sadb_msg_type]++; + } + + for (rp = rawcb.lh_first; rp; rp = rp->rcb_list.le_next) { if (rp->rcb_proto.sp_family != PF_KEY) continue; @@ -449,13 +440,17 @@ key_sendup(so, msg, len, target) sendup++; break; } + pfkeystat.in_msgtarget[target]++; if (!sendup) continue; if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) { +#ifdef IPSEC_DEBUG printf("key_sendup: m_copy fail\n"); +#endif m_freem(m); + pfkeystat.in_nomem++; return ENOBUFS; } @@ -472,10 +467,6 @@ key_sendup(so, msg, len, target) return error; } -#ifdef __FreeBSD__ -/* sysctl */ -SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW, 0, "Key Family"); -#endif /* * Definitions of protocols supported in the KEY domain. @@ -488,9 +479,7 @@ struct protosw keysw[] = { 0, key_output, raw_ctlinput, 0, key_usrreq, raw_init, 0, 0, 0, -#if defined(__bsdi__) || defined(__NetBSD__) key_sysctl, -#endif } }; @@ -498,6 +487,3 @@ struct domain keydomain = { PF_KEY, "key", key_init, 0, 0, keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] }; -#ifdef __FreeBSD__ -DOMAIN_SET(key); -#endif diff --git a/sys/netkey/keysock.h b/sys/netkey/keysock.h index 27aebf65e857..65c9fb3ecd80 100644 --- a/sys/netkey/keysock.h +++ b/sys/netkey/keysock.h @@ -1,4 +1,4 @@ -/* $NetBSD: keysock.h,v 1.4 1999/07/06 12:23:26 itojun Exp $ */ +/* $NetBSD: keysock.h,v 1.5 2000/01/31 14:19:13 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,41 +29,60 @@ * SUCH DAMAGE. */ -/* KAME Id: keysock.h,v 1.1.6.3.6.1 1999/05/17 17:03:19 itojun Exp */ +/* KAME Id: keysock.h,v 1.5 2000/01/29 06:21:03 itojun Exp */ #ifndef _NETKEY_KEYSOCK_H_ #define _NETKEY_KEYSOCK_H_ -#ifdef __NetBSD__ -# ifdef _KERNEL -# define KERNEL -# endif -#endif +/* statistics for pfkey socket */ +struct pfkeystat { + /* kernel -> userland */ + u_quad_t out_total; /* # of total calls */ + u_quad_t out_bytes; /* total bytecount */ + u_quad_t out_msgtype[256]; /* message type histogram */ + u_quad_t out_invlen; /* invalid length field */ + u_quad_t out_invver; /* invalid version field */ + u_quad_t out_invmsgtype; /* invalid message type field */ + u_quad_t out_tooshort; /* msg too short */ + u_quad_t out_nomem; /* memory allocation failure */ + u_quad_t out_dupext; /* duplicate extension */ + u_quad_t out_invexttype; /* invalid extension type */ + u_quad_t out_invsatype; /* invalid sa type */ + u_quad_t out_invaddr; /* invalid address extension */ + /* userland -> kernel */ + u_quad_t in_total; /* # of total calls */ + u_quad_t in_bytes; /* total bytecount */ + u_quad_t in_msgtype[256]; /* message type histogram */ + u_quad_t in_msgtarget[3]; /* one/all/registered */ + u_quad_t in_nomem; /* memory allocation failure */ + /* others */ + u_quad_t sockerr; /* # of socket related errors */ +}; -#if defined(KERNEL) +#define KEY_SENDUP_ONE 0 +#define KEY_SENDUP_ALL 1 +#define KEY_SENDUP_REGISTERED 2 + +#ifdef _KERNEL struct keycb { struct rawcb kp_raw; /* rawcb */ int kp_promisc; /* promiscuous mode */ int kp_registered; /* registered socket */ }; +extern struct pfkeystat pfkeystat; + extern int key_output __P((struct mbuf *, ...)); #ifndef __NetBSD__ -extern int key_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *)); +extern int key_usrreq __P((struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *)); #else extern int key_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); #endif -#define KEY_SENDUP_ONE 0 -#define KEY_SENDUP_ALL 1 -#define KEY_SENDUP_REGISTERED 2 - extern int key_sendup __P((struct socket *, struct sadb_msg *, u_int, int)); -#else -#if 0 /* no library defined for this */ -extern int key_sendup __P((int, struct sadb_msg *, u_int, int)); -#endif -#endif /* defined(KERNEL) */ +extern int key_sendup_mbuf __P((struct socket *, struct mbuf *, int)); +#endif /* _KERNEL */ -#endif _NETKEY_KEYSOCK_H_ +#endif /*_NETKEY_KEYSOCK_H_*/ diff --git a/sys/netkey/keyv2.h b/sys/netkey/keyv2.h index dd6d07df9b5c..34cd140901bf 100644 --- a/sys/netkey/keyv2.h +++ b/sys/netkey/keyv2.h @@ -1,4 +1,4 @@ -/* $NetBSD: keyv2.h,v 1.5 1999/07/06 12:23:26 itojun Exp $ */ +/* $NetBSD: keyv2.h,v 1.6 2000/01/31 14:19:14 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,7 +29,7 @@ * SUCH DAMAGE. */ -/* KAME Id: keyv2.h,v 1.1.6.1.6.4 1999/06/08 05:33:39 itojun Exp */ +/* KAME Id: keyv2.h,v 1.14 2000/01/29 06:21:03 itojun Exp */ /* * This file has been derived rfc 2367, @@ -40,12 +40,6 @@ #ifndef _NETKEY_KEYV2_H_ #define _NETKEY_KEYV2_H_ -#ifdef __NetBSD__ -# ifdef _KERNEL -# define KERNEL -# endif -#endif - /* This file defines structures and symbols for the PF_KEY Version 2 key management interface. It was written at the U.S. Naval Research @@ -71,11 +65,17 @@ you leave this credit intact on any copies of this file. #define SADB_DUMP 10 #define SADB_X_PROMISC 11 #define SADB_X_PCHANGE 12 -#define SADB_X_SPDADD 13 -#define SADB_X_SPDDELETE 14 -#define SADB_X_SPDDUMP 15 -#define SADB_X_SPDFLUSH 16 -#define SADB_MAX 16 + +#define SADB_X_SPDUPDATE 13 /* not yet */ +#define SADB_X_SPDADD 14 +#define SADB_X_SPDDELETE 15 +#define SADB_X_SPDGET 16 /* not yet */ +#define SADB_X_SPDACQUIRE 17 /* not yet */ +#define SADB_X_SPDDUMP 18 +#define SADB_X_SPDFLUSH 19 +#define SADB_X_SPDSETIDX 20 /* add only SPD selector */ +#define SADB_X_SPDEXPIRE 21 /* not yet */ +#define SADB_MAX 21 struct sadb_msg { u_int8_t sadb_msg_version; @@ -83,9 +83,13 @@ struct sadb_msg { u_int8_t sadb_msg_errno; u_int8_t sadb_msg_satype; u_int16_t sadb_msg_len; - u_int16_t sadb_msg_reserved; + u_int8_t sadb_msg_mode; /* XXX */ + u_int8_t sadb_msg_reserved1; u_int32_t sadb_msg_seq; u_int32_t sadb_msg_pid; + u_int32_t sadb_msg_reqid; /* XXX */ + /* when policy mng, value is zero. */ + u_int32_t sadb_msg_reserved2; }; struct sadb_ext { @@ -135,6 +139,15 @@ struct sadb_ident { u_int16_t sadb_ident_reserved; u_int64_t sadb_ident_id; }; +/* in order to use to divide sadb_ident.sadb_ident_id */ +union sadb_x_ident_id { + u_int64_t sadb_x_ident_id; + struct _sadb_x_ident_id_addr { + u_int16_t prefix; + u_int16_t ul_proto; + u_int32_t reserved; + } sadb_x_ident_id_addr; +}; struct sadb_sens { u_int16_t sadb_sens_len; @@ -206,28 +219,37 @@ struct sadb_x_kmprivate { struct sadb_x_policy { u_int16_t sadb_x_policy_len; u_int16_t sadb_x_policy_exttype; - u_int16_t sadb_x_policy_type; /* See ipsec.h */ - u_int16_t sadb_x_policy_reserved; + u_int16_t sadb_x_policy_type; /* See policy type of ipsec.h */ + u_int8_t sadb_x_policy_dir; /* direction, see ipsec.h */ + u_int8_t sadb_x_policy_reserved; }; /* - * followed by some of the ipsec policy request, if policy_type == IPSEC. + * When policy_type == IPSEC, it is followed by some of + * the ipsec policy request. * [total length of ipsec policy requests] * = (sadb_x_policy_len * sizeof(uint64_t) - sizeof(struct sadb_x_policy)) */ /* XXX IPsec Policy Request Extension */ /* - * This structure is aligned 8 bytes. Also it's aligned with proxy address - * if present. + * This structure is aligned 8 bytes. */ struct sadb_x_ipsecrequest { - u_int16_t sadb_x_ipsecrequest_len; /* structure length aligned 8 bytes. + u_int16_t sadb_x_ipsecrequest_len; /* structure length aligned to 8 bytes. * This value is true length of bytes. * Not in units of 64 bits. */ u_int16_t sadb_x_ipsecrequest_proto; /* See ipsec.h */ - u_int16_t sadb_x_ipsecrequest_mode; /* See ipsec.h */ - u_int16_t sadb_x_ipsecrequest_level; /* See ipsec.h */ - /* If mode != 0, the proxy address encoded struct sockaddr is following. */ + u_int8_t sadb_x_ipsecrequest_mode; /* See IPSEC_MODE_XX in ipsec.h. */ + u_int8_t sadb_x_ipsecrequest_level; /* See IPSEC_LEVEL_XX in ipsec.h */ + u_int16_t sadb_x_ipsecrequest_reqid; /* See ipsec.h */ + + /* + * followed by source IP address of SA, and immediately followed by + * destination IP address of SA. These encoded into two of sockaddr + * structure without any padding. Must set each sa_len exactly. + * Each of length of the sockaddr structure are not aligned to 64bits, + * but sum of x_request and addresses is aligned to 64bits. + */ }; #define SADB_EXT_RESERVED 0 @@ -295,28 +317,34 @@ struct sadb_x_ipsecrequest { #define SADB_X_CALG_OUI 1 #define SADB_X_CALG_DEFLATE 2 #define SADB_X_CALG_LZS 3 +#define SADB_X_CALG_MAX 4 #endif #define SADB_IDENTTYPE_RESERVED 0 #define SADB_IDENTTYPE_PREFIX 1 #define SADB_IDENTTYPE_FQDN 2 #define SADB_IDENTTYPE_USERFQDN 3 -#define SADB_IDENTTYPE_MAX 3 +#define SADB_X_IDENTTYPE_ADDR 4 +#define SADB_IDENTTYPE_MAX 4 -/* `flags' in SA structure holds followings */ +/* `flags' in sadb_sa structure holds followings */ #define SADB_X_EXT_NONE 0x0000 /* i.e. new format. */ #define SADB_X_EXT_OLD 0x0001 /* old format. */ + #define SADB_X_EXT_IV4B 0x0010 /* IV length of 4 bytes in use */ #define SADB_X_EXT_DERIV 0x0020 /* DES derived */ #define SADB_X_EXT_CYCSEQ 0x0040 /* allowing to cyclic sequence. */ - /* the followings are exclusive flags */ + + /* three of followings are exclusive flags each them */ #define SADB_X_EXT_PSEQ 0x0000 /* sequencial padding for ESP */ #define SADB_X_EXT_PRAND 0x0100 /* random padding for ESP */ -#define SADB_X_EXT_PZERO 0x0300 /* zero padding for ESP */ +#define SADB_X_EXT_PZERO 0x0200 /* zero padding for ESP */ #define SADB_X_EXT_PMASK 0x0300 /* mask for padding flag */ + #if 1 #define SADB_X_EXT_RAWCPI 0x0080 /* use well known CPI (IPComp) */ #endif + #define SADB_KEY_FLAGS_MAX 0x0fff /* SPI size for PF_KEYv2 */ @@ -351,57 +379,48 @@ struct sadb_x_ipsecrequest { #define PFKEY_UNIT64(a) (a) #endif -#ifndef KERNEL -extern void pfkey_sadump(struct sadb_msg *m); -extern void pfkey_spdump(struct sadb_msg *m); +#ifndef _KERNEL +extern void pfkey_sadump __P((struct sadb_msg *)); +extern void pfkey_spdump __P((struct sadb_msg *)); struct sockaddr; -extern int ipsec_check_keylen(u_int supported, u_int alg_id, u_int keylen); -extern int pfkey_check(struct sadb_msg *msg, caddr_t *mhp); -extern u_int pfkey_set_softrate(u_int type, u_int rate); -extern u_int pfkey_get_softrate(u_int type); -extern int pfkey_send_getspi(int so, u_int satype, - struct sockaddr *src, u_int prefs, - struct sockaddr *dst, u_int prefd, u_int proto, - u_int32_t min, u_int32_t max, u_int32_t seq); -extern int pfkey_send_update( int so, u_int satype, - struct sockaddr *src, u_int prefs, - struct sockaddr *dst, u_int prefd, u_int proto, - struct sockaddr *proxy, - u_int32_t spi, caddr_t keymat, - u_int e_type, u_int e_keylen, u_int a_type, u_int a_keylen, - u_int flags, - u_int32_t l_alloc, u_int32_t l_bytes, - u_int32_t l_addtime, u_int32_t l_usetime, u_int32_t seq); -extern int pfkey_send_add( int so, u_int satype, - struct sockaddr *src, u_int prefs, - struct sockaddr *dst, u_int prefd, u_int proto, - struct sockaddr *proxy, - u_int32_t spi, caddr_t keymat, - u_int e_type, u_int e_keylen, u_int a_type, u_int a_keylen, - u_int flags, - u_int32_t l_alloc, u_int32_t l_bytes, - u_int32_t l_addtime, u_int32_t l_usetime, u_int32_t seq); -extern int pfkey_send_delete( int so, u_int satype, - struct sockaddr *src, u_int prefs, - struct sockaddr *dst, u_int prefd, u_int proto, - u_int32_t spi); -extern int pfkey_send_get( int so, u_int satype, - struct sockaddr *src, u_int prefs, - struct sockaddr *dst, u_int prefd, u_int proto, - u_int32_t spi); -extern int pfkey_send_register(int so, u_int satype); -extern int pfkey_recv_register(int so); -extern int pfkey_send_flush(int so, u_int satype); -extern int pfkey_send_dump(int so, u_int satype); -extern int pfkey_send_promisc_toggle(int so, int flag); +int ipsec_check_keylen __P((u_int, u_int, u_int)); +u_int pfkey_set_softrate __P((u_int, u_int)); +u_int pfkey_get_softrate __P((u_int)); +int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t)); +int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, + u_int64_t, u_int64_t, u_int32_t)); +int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, + u_int64_t, u_int64_t, u_int32_t)); +int pfkey_send_delete __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_get __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_register __P((int, u_int)); +int pfkey_recv_register __P((int)); +int pfkey_send_flush __P((int, u_int)); +int pfkey_send_dump __P((int, u_int)); +int pfkey_send_promisc_toggle __P((int, int)); +int pfkey_send_spdadd __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spddelete __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int32_t)); +int pfkey_send_spdflush __P((int)); +int pfkey_send_spddump __P((int)); -extern int pfkey_open(void); -extern void pfkey_close(int so); -extern struct sadb_msg *pfkey_recv(int so); -extern int pfkey_send(int so, struct sadb_msg *msg, int len); +int pfkey_open __P((void)); +void pfkey_close __P((int)); +struct sadb_msg *pfkey_recv __P((int)); +int pfkey_send __P((int, struct sadb_msg *, int)); +int pfkey_align __P((struct sadb_msg *, caddr_t *)); +int pfkey_check __P((caddr_t *)); -#endif /*!KERNEL*/ +#endif /*!_KERNEL*/ #endif /* __PFKEY_V2_H */