#include <sys/kernel.h>
#include <sys/syslog.h>
#include <sys/sysctl.h>
+#include <kern/locks.h>
+#include <sys/kauth.h>
#include <net/if.h>
#include <net/route.h>
int ipsec_debug = 0;
#endif
+#include <sys/kdebug.h>
+#define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1)
+#define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3)
+#define DBG_FNC_GETPOL_SOCK NETDBG_CODE(DBG_NETIPSEC, (1 << 8))
+#define DBG_FNC_GETPOL_ADDR NETDBG_CODE(DBG_NETIPSEC, (2 << 8))
+#define DBG_FNC_IPSEC_OUT NETDBG_CODE(DBG_NETIPSEC, (3 << 8))
+
+extern lck_mtx_t *sadb_mutex;
+extern lck_mtx_t *ip6_mutex;
+
struct ipsecstat ipsecstat;
int ip4_ah_cleartos = 1;
int ip4_ah_offsetmask = 0; /* maybe IP_DF? */
struct secpolicy ip4_def_policy;
int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */
int ip4_esp_randpad = -1;
+int esp_udp_encap_port = 0;
static int sysctl_def_policy SYSCTL_HANDLER_ARGS;
+extern u_int32_t natt_now;
SYSCTL_DECL(_net_inet_ipsec);
#if INET6
int ipsec_bypass = 1;
SYSCTL_INT(_net_inet_ipsec, OID_AUTO, bypass, CTLFLAG_RD, &ipsec_bypass,0, "");
+/*
+ * NAT Traversal requires a UDP port for encapsulation,
+ * esp_udp_encap_port controls which port is used. Racoon
+ * must set this port to the port racoon is using locally
+ * for nat traversal.
+ */
+SYSCTL_INT(_net_inet_ipsec, OID_AUTO, esp_port,
+ CTLFLAG_RW, &esp_udp_encap_port, 0, "");
+
#if INET6
struct ipsecstat ipsec6stat;
int ip6_esp_trans_deflev = IPSEC_LEVEL_USE;
esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, "");
#endif /* INET6 */
-static int ipsec_setspidx_mbuf
- __P((struct secpolicyindex *, u_int, u_int, struct mbuf *, int));
-static int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb));
+static int ipsec_setspidx_mbuf(struct secpolicyindex *, u_int, u_int,
+ struct mbuf *, int);
+static int ipsec4_setspidx_inpcb(struct mbuf *, struct inpcb *pcb);
#if INET6
-static int ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb));
+static int ipsec6_setspidx_in6pcb(struct mbuf *, struct in6pcb *pcb);
#endif
-static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int));
-static void ipsec4_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int));
-static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
+static int ipsec_setspidx(struct mbuf *, struct secpolicyindex *, int);
+static void ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *, int);
+static int ipsec4_setspidx_ipaddr(struct mbuf *, struct secpolicyindex *);
#if INET6
-static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int));
-static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
+static void ipsec6_get_ulp(struct mbuf *m, struct secpolicyindex *, int);
+static int ipsec6_setspidx_ipaddr(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 *));
+static struct inpcbpolicy *ipsec_newpcbpolicy(void);
+static void ipsec_delpcbpolicy(struct inpcbpolicy *);
+static struct secpolicy *ipsec_deepcopy_policy(struct secpolicy *src);
+static int ipsec_set_policy(struct secpolicy **pcb_sp,
+ int optname, caddr_t request, size_t len, int priv);
+static int ipsec_get_policy(struct secpolicy *pcb_sp, struct mbuf **mp);
+static void vshiftl(unsigned char *, int, int);
+static int ipsec_in_reject(struct secpolicy *, struct mbuf *);
+static size_t ipsec_hdrsiz(struct secpolicy *);
#if INET
-static struct mbuf *ipsec4_splithdr __P((struct mbuf *));
+static struct mbuf *ipsec4_splithdr(struct mbuf *);
#endif
#if INET6
-static struct mbuf *ipsec6_splithdr __P((struct mbuf *));
+static struct mbuf *ipsec6_splithdr(struct mbuf *);
#endif
#if INET
-static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *));
+static int ipsec4_encapsulate(struct mbuf *, struct secasvar *);
#endif
#if INET6
-static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *));
+static int ipsec6_encapsulate(struct mbuf *, struct secasvar *);
#endif
-static struct mbuf *ipsec_addaux __P((struct mbuf *));
-static struct mbuf *ipsec_findaux __P((struct mbuf *));
-static void ipsec_optaux __P((struct mbuf *, struct mbuf *));
+static struct mbuf *ipsec_addaux(struct mbuf *);
+static struct mbuf *ipsec_findaux(struct mbuf *);
+static void ipsec_optaux(struct mbuf *, struct mbuf *);
+void ipsec_send_natt_keepalive(struct secasvar *sav);
static int
sysctl_def_policy SYSCTL_HANDLER_ARGS
* 0 : bypass
* EACCES : discard packet.
* ENOENT : ipsec_acquire() in progress, maybe.
- * others : error occured.
+ * others : error occurred.
* others: a pointer to SP
*
* NOTE: IPv6 mapped adddress concern is implemented here.
struct secpolicy *currsp = NULL; /* policy on socket */
struct secpolicy *kernsp = NULL; /* policy on kernel */
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
/* sanity check */
if (m == NULL || so == NULL || error == NULL)
panic("ipsec4_getpolicybysock: NULL pointer was passed.\n");
+ if (so->so_pcb == NULL) {
+ printf("ipsec4_getpolicybysock: so->so_pcb == NULL\n");
+ return ipsec4_getpolicybyaddr(m, dir, 0, error);
+ }
+
switch (so->so_proto->pr_domain->dom_family) {
case AF_INET:
pcbsp = sotoinpcb(so)->inp_sp;
return ipsec4_getpolicybyaddr(m, dir, 0, error);
}
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_START, 0,0,0,0,0);
+
switch (so->so_proto->pr_domain->dom_family) {
case AF_INET:
/* set spidx in pcb */
default:
panic("ipsec4_getpolicybysock: unsupported address family\n");
}
- if (*error)
+ if (*error) {
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 1,*error,0,0,0);
return NULL;
+ }
/* sanity check */
if (pcbsp == NULL)
case IPSEC_POLICY_BYPASS:
currsp->refcnt++;
*error = 0;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 2,*error,0,0,0);
return currsp;
case IPSEC_POLICY_ENTRUST:
printf("DP ipsec4_getpolicybysock called "
"to allocate SP:%p\n", kernsp));
*error = 0;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 3,*error,0,0,0);
return kernsp;
}
}
ip4_def_policy.refcnt++;
*error = 0;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 4,*error,0,0,0);
return &ip4_def_policy;
case IPSEC_POLICY_IPSEC:
currsp->refcnt++;
*error = 0;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 5,*error,0,0,0);
return currsp;
default:
ipseclog((LOG_ERR, "ipsec4_getpolicybysock: "
"Invalid policy for PCB %d\n", currsp->policy));
*error = EINVAL;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 6,*error,0,0,0);
return NULL;
}
/* NOTREACHED */
printf("DP ipsec4_getpolicybysock called "
"to allocate SP:%p\n", kernsp));
*error = 0;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 7,*error,0,0,0);
return kernsp;
}
"Illegal policy for non-priviliged defined %d\n",
currsp->policy));
*error = EINVAL;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 8,*error,0,0,0);
return NULL;
case IPSEC_POLICY_ENTRUST:
}
ip4_def_policy.refcnt++;
*error = 0;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 9,*error,0,0,0);
return &ip4_def_policy;
case IPSEC_POLICY_IPSEC:
currsp->refcnt++;
*error = 0;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 10,*error,0,0,0);
return currsp;
default:
ipseclog((LOG_ERR, "ipsec4_getpolicybysock: "
"Invalid policy for PCB %d\n", currsp->policy));
*error = EINVAL;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_SOCK | DBG_FUNC_END, 11,*error,0,0,0);
return NULL;
}
/* NOTREACHED */
* 0 : bypass
* EACCES : discard packet.
* ENOENT : ipsec_acquire() in progress, maybe.
- * others : error occured.
+ * others : error occurred.
*/
struct secpolicy *
ipsec4_getpolicybyaddr(m, dir, flag, error)
if (ipsec_bypass != 0)
return 0;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check */
if (m == NULL || error == NULL)
panic("ipsec4_getpolicybyaddr: NULL pointer was passed.\n");
{
struct secpolicyindex spidx;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_ADDR | DBG_FUNC_START, 0,0,0,0,0);
bzero(&spidx, sizeof(spidx));
/* make a index to look for a policy */
*error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m,
(flag & IP_FORWARDING) ? 0 : 1);
- if (*error != 0)
+ if (*error != 0) {
+ KERNEL_DEBUG(DBG_FNC_GETPOL_ADDR | DBG_FUNC_END, 1,*error,0,0,0);
return NULL;
+ }
sp = key_allocsp(&spidx, dir);
}
printf("DP ipsec4_getpolicybyaddr called "
"to allocate SP:%p\n", sp));
*error = 0;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_ADDR | DBG_FUNC_END, 2,*error,0,0,0);
return sp;
}
}
ip4_def_policy.refcnt++;
*error = 0;
+ KERNEL_DEBUG(DBG_FNC_GETPOL_ADDR | DBG_FUNC_END, 3,*error,0,0,0);
return &ip4_def_policy;
}
* 0 : bypass
* EACCES : discard packet.
* ENOENT : ipsec_acquire() in progress, maybe.
- * others : error occured.
+ * others : error occurred.
* others: a pointer to SP
*/
struct secpolicy *
struct secpolicy *currsp = NULL; /* policy on socket */
struct secpolicy *kernsp = NULL; /* policy on kernel */
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check */
if (m == NULL || so == NULL || error == NULL)
panic("ipsec6_getpolicybysock: NULL pointer was passed.\n");
* 0 : bypass
* EACCES : discard packet.
* ENOENT : ipsec_acquire() in progress, maybe.
- * others : error occured.
+ * others : error occurred.
*/
#ifndef IP_FORWARDING
#define IP_FORWARDING 1
{
struct secpolicy *sp = NULL;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check */
if (m == NULL || error == NULL)
panic("ipsec6_getpolicybyaddr: NULL pointer was passed.\n");
goto bad;
spidx->dir = IPSEC_DIR_INBOUND;
- KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
- printf("ipsec_setspidx_mbuf: end\n");
- kdebug_secpolicyindex(spidx));
+ spidx = &pcb->in6p_sp->sp_out->spidx;
+ error = ipsec_setspidx(m, spidx, 1);
+ if (error)
+ goto bad;
+ spidx->dir = IPSEC_DIR_OUTBOUND;
return 0;
uh.uh_dport;
return;
case IPPROTO_AH:
- if (m->m_pkthdr.len > off + sizeof(ip6e))
+ if (off + sizeof(ip6e) > m->m_pkthdr.len)
return;
m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
off += (ip6e.ip6e_len + 2) << 2;
{
struct inpcbpolicy *new;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check. */
if (so == NULL || pcb_sp == NULL)
panic("ipsec_init_policy: NULL pointer was passed.\n");
#ifdef __APPLE__
if (so->so_uid == 0)
#else
- if (so->so_cred != 0 && so->so_cred->pc_ucred->cr_uid == 0)
+ if (so->so_cred != 0 && !suser(so->so_cred->pc_ucred, NULL))
#endif
new->priv = 1;
else
if (ipsec_bypass != 0)
return 0;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
sp = ipsec_deepcopy_policy(old->sp_in);
if (sp) {
key_freesp(new->sp_in);
struct secpolicy *newsp = NULL;
int error;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check. */
if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL)
return EINVAL;
struct mbuf **mp;
{
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check. */
if (pcb_sp == NULL || mp == NULL)
return EINVAL;
struct secpolicy **pcb_sp;
int error = 0;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check. */
if (inp == NULL || request == NULL)
return EINVAL;
struct secpolicy *pcb_sp;
int error = 0;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check. */
if (inp == NULL || request == NULL || mp == NULL)
return EINVAL;
ipsec4_delete_pcbpolicy(inp)
struct inpcb *inp;
{
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check. */
if (inp == NULL)
panic("ipsec4_delete_pcbpolicy: NULL pointer was passed.\n");
struct secpolicy **pcb_sp;
int error = 0;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check. */
if (in6p == NULL || request == NULL)
return EINVAL;
struct secpolicy *pcb_sp;
int error = 0;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check. */
if (in6p == NULL || request == NULL || mp == NULL)
return EINVAL;
ipsec6_delete_pcbpolicy(in6p)
struct in6pcb *in6p;
{
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check. */
if (in6p == NULL)
panic("ipsec6_delete_pcbpolicy: NULL pointer was passed.\n");
u_int level = 0;
u_int esp_trans_deflev, esp_net_deflev, ah_trans_deflev, ah_net_deflev;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check */
if (isr == NULL || isr->sp == NULL)
panic("ipsec_get_reqlevel: NULL pointer is passed.\n");
level = ah_net_deflev;
else
level = ah_trans_deflev;
+ break;
case IPPROTO_IPCOMP:
/*
* we don't really care, as IPcomp document says that
printf("ipsec_in_reject: using SP\n");
kdebug_secpolicy(sp));
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* check policy */
switch (sp->policy) {
case IPSEC_POLICY_DISCARD:
int error;
int result;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check */
if (m == NULL)
return 0; /* XXX should be panic ? */
struct mbuf *m;
struct inpcb *inp;
{
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
if (inp == NULL)
return ipsec4_in_reject_so(m, NULL);
if (inp->inp_socket)
return ipsec4_in_reject_so(m, inp->inp_socket);
else
panic("ipsec4_in_reject: invalid inpcb/socket");
+
+ /* NOTREACHED */
+ return 0;
}
#if INET6
int error;
int result;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check */
if (m == NULL)
return 0; /* XXX should be panic ? */
struct mbuf *m;
struct in6pcb *in6p;
{
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
if (in6p == NULL)
return ipsec6_in_reject_so(m, NULL);
if (in6p->in6p_socket)
return ipsec6_in_reject_so(m, in6p->in6p_socket);
else
panic("ipsec6_in_reject: invalid in6p/socket");
+
+ /* NOTREACHED */
+ return 0;
}
#endif
size_t siz, clen;
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
- printf("ipsec_in_reject: using SP\n");
+ printf("ipsec_hdrsiz: using SP\n");
kdebug_secpolicy(sp));
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* check policy */
switch (sp->policy) {
case IPSEC_POLICY_DISCARD:
int error;
size_t size;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check */
if (m == NULL)
return 0; /* XXX should be panic ? */
int error;
size_t size;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check */
if (m == NULL)
return 0; /* XXX shoud be panic ? */
size_t hlen;
size_t plen;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* can't tunnel between different AFs */
if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
!= ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family
ip->ip_off &= htons(~IP_OFFMASK);
ip->ip_off &= htons(~IP_MF);
switch (ip4_ipsec_dfbit) {
- case 0: /*clear DF bit*/
+ case 0: /* clear DF bit */
ip->ip_off &= htons(~IP_DF);
break;
- case 1: /*set DF bit*/
+ case 1: /* set DF bit */
ip->ip_off |= htons(IP_DF);
break;
- default: /*copy DF bit*/
+ default: /* copy DF bit */
break;
}
ip->ip_p = IPPROTO_IPIP;
struct ip6_hdr *ip6;
size_t plen;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* can't tunnel between different AFs */
if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
!= ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family
u_int32_t wsizeb; /* constant: bits of window size */
int frlast; /* constant: last frame */
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check */
if (sav == NULL)
panic("ipsec_chkreplay: NULL pointer was passed.\n");
u_int32_t wsizeb; /* constant: bits of window size */
int frlast; /* constant: last frame */
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* sanity check */
if (sav == NULL)
panic("ipsec_chkreplay: NULL pointer was passed.\n");
}
/*
- * shift variable length bunffer to left.
+ * shift variable length buffer to left.
* IN: bitmap: pointer to the buffer
* nbit: the number of to shift.
* wsize: buffer size (bytes).
char *p;
struct secasindex *saidx = &sav->sah->saidx;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
/* validity check */
if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
!= ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family)
struct ip *ip = NULL;
struct ipsecrequest *isr = NULL;
struct secasindex saidx;
- int s;
int error;
struct sockaddr_in *dst4;
struct sockaddr_in *sin;
if (!state->dst)
panic("state->dst == NULL in ipsec4_output");
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
+ KERNEL_DEBUG(DBG_FNC_IPSEC_OUT | DBG_FUNC_START, 0,0,0,0,0);
+
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
printf("ipsec4_output: applyed SP\n");
kdebug_secpolicy(sp));
* There may be the case that SA status will be changed when
* we are refering to one. So calling splsoftnet().
*/
- s = splnet();
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
/*
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;
}
state->m = ipsec4_splithdr(state->m);
if (!state->m) {
- splx(s);
error = ENOMEM;
goto bad;
}
error = ipsec4_encapsulate(state->m, isr->sav);
- splx(s);
if (error) {
state->m = NULL;
goto bad;
state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway;
dst4 = (struct sockaddr_in *)state->dst;
}
- } else
- splx(s);
+ }
state->m = ipsec4_splithdr(state->m);
if (!state->m) {
ip = mtod(state->m, struct ip *);
}
+ KERNEL_DEBUG(DBG_FNC_IPSEC_OUT | DBG_FUNC_END, 0,0,0,0,0);
return 0;
bad:
m_freem(state->m);
state->m = NULL;
+ KERNEL_DEBUG(DBG_FNC_IPSEC_OUT | DBG_FUNC_END, error,0,0,0,0);
return error;
}
#endif
struct sockaddr_in6 *sin6;
if (!state)
- panic("state == NULL in ipsec6_output");
+ panic("state == NULL in ipsec6_output_trans");
if (!state->m)
- panic("state->m == NULL in ipsec6_output");
+ panic("state->m == NULL in ipsec6_output_trans");
if (!nexthdrp)
- panic("nexthdrp == NULL in ipsec6_output");
+ panic("nexthdrp == NULL in ipsec6_output_trans");
if (!mprev)
- panic("mprev == NULL in ipsec6_output");
+ panic("mprev == NULL in ipsec6_output_trans");
if (!sp)
- panic("sp == NULL in ipsec6_output");
+ panic("sp == NULL in ipsec6_output_trans");
if (!tun)
- panic("tun == NULL in ipsec6_output");
+ panic("tun == NULL in ipsec6_output_trans");
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
printf("ipsec6_output_trans: applyed SP\n");
kdebug_secpolicy(sp));
-
+
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
*tun = 0;
for (isr = sp->req; isr; isr = isr->next) {
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
* XXX: should we directly notify sockets via
* pfctlinputs?
*/
+ lck_mtx_unlock(sadb_mutex);
icmp6_error(state->m, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_ADMIN, 0);
+ lck_mtx_lock(sadb_mutex);
state->m = NULL; /* icmp6_error freed the mbuf */
goto bad;
}
int error = 0;
int plen;
struct sockaddr_in6* dst6;
- int s;
if (!state)
- panic("state == NULL in ipsec6_output");
+ panic("state == NULL in ipsec6_output_tunnel");
if (!state->m)
- panic("state->m == NULL in ipsec6_output");
+ panic("state->m == NULL in ipsec6_output_tunnel");
if (!sp)
- panic("sp == NULL in ipsec6_output");
+ panic("sp == NULL in ipsec6_output_tunnel");
+
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
printf("ipsec6_output_tunnel: applyed SP\n");
break;
}
- for (/*already initialized*/; isr; isr = isr->next) {
- /* When tunnel mode, SA peers must be specified. */
- bcopy(&isr->saidx, &saidx, sizeof(saidx));
+ for (/* already initialized */; isr; isr = isr->next) {
+ if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
+ /* When tunnel mode, SA peers must be specified. */
+ bcopy(&isr->saidx, &saidx, sizeof(saidx));
+ } else {
+ /* make SA index to look for a proper SA */
+ struct sockaddr_in6 *sin6;
+
+ bzero(&saidx, sizeof(saidx));
+ saidx.proto = isr->saidx.proto;
+ saidx.mode = isr->saidx.mode;
+ saidx.reqid = isr->saidx.reqid;
+
+ ip6 = mtod(state->m, struct ip6_hdr *);
+ sin6 = (struct sockaddr_in6 *)&saidx.src;
+ if (sin6->sin6_len == 0) {
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = IPSEC_PORT_ANY;
+ bcopy(&ip6->ip6_src, &sin6->sin6_addr,
+ sizeof(ip6->ip6_src));
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
+ /* fix scope id for comparing SPD */
+ sin6->sin6_addr.s6_addr16[1] = 0;
+ sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
+ }
+ }
+ sin6 = (struct sockaddr_in6 *)&saidx.dst;
+ if (sin6->sin6_len == 0) {
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = IPSEC_PORT_ANY;
+ bcopy(&ip6->ip6_dst, &sin6->sin6_addr,
+ sizeof(ip6->ip6_dst));
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
+ /* fix scope id for comparing SPD */
+ sin6->sin6_addr.s6_addr16[1] = 0;
+ sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
+ }
+ }
+ }
+
if (key_checkrequest(isr, &saidx) == ENOENT) {
/*
* IPsec processing is required, but no SA found.
* There may be the case that SA status will be changed when
* we are refering to one. So calling splsoftnet().
*/
- s = splnet();
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
/*
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;
state->m = ipsec6_splithdr(state->m);
if (!state->m) {
- splx(s);
ipsec6stat.out_nomem++;
error = ENOMEM;
goto bad;
}
error = ipsec6_encapsulate(state->m, isr->sav);
- splx(s);
if (error) {
state->m = 0;
goto bad;
state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway;
dst6 = (struct sockaddr_in6 *)state->dst;
}
- } else
- splx(s);
+ }
state->m = ipsec6_splithdr(state->m);
if (!state->m) {
struct secpolicy *sp;
struct ip *oip;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
#if DIAGNOSTIC
if (m->m_len < sizeof(struct ip))
panic("too short mbuf on ipsec4_tunnel_validate");
sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst,
(struct sockaddr *)&isrc, (struct sockaddr *)&idst);
- if (!sp)
+ if (!sp) {
return 0;
+ }
key_freesp(sp);
return 1;
struct secpolicy *sp;
struct ip6_hdr *oip6;
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
#if DIAGNOSTIC
if (m->m_len < sizeof(struct ip6_hdr))
panic("too short mbuf on ipsec6_tunnel_validate");
sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst,
(struct sockaddr *)&isrc, (struct sockaddr *)&idst);
+ /*
+ * when there is no suitable inbound policy for the packet of the ipsec
+ * tunnel mode, the kernel never decapsulate the tunneled packet
+ * as the ipsec tunnel mode even when the system wide policy is "none".
+ * then the kernel leaves the generic tunnel module to process this
+ * packet. if there is no rule of the generic tunnel, the packet
+ * is rejected and the statistics will be counted up.
+ */
if (!sp)
return 0;
key_freesp(sp);
if (!n)
return ENOBUFS;
if (M_TRAILINGSPACE(n) < sizeof(*p))
- return ENOSPC; /*XXX*/
+ return ENOSPC; /* XXX */
p = (struct ipsec_history *)(mtod(n, caddr_t) + n->m_len);
n->m_len += sizeof(*p);
bzero(p, sizeof(*p));
n->m_len = sizeof(struct socket *);
ipsec_optaux(m, n);
}
+
+__private_extern__ void
+ipsec_send_natt_keepalive(
+ struct secasvar *sav)
+{
+ struct mbuf *m;
+ struct udphdr *uh;
+ struct ip *ip;
+ int error;
+
+ if ((esp_udp_encap_port & 0xFFFF) == 0 || sav->remote_ike_port == 0) return;
+
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+
+ m = m_gethdr(M_NOWAIT, MT_DATA);
+ if (m == NULL) return;
+
+ /*
+ * Create a UDP packet complete with IP header.
+ * We must do this because UDP output requires
+ * an inpcb which we don't have. UDP packet
+ * contains one byte payload. The byte is set
+ * to 0xFF.
+ */
+ ip = (struct ip*)m_mtod(m);
+ uh = (struct udphdr*)((char*)m_mtod(m) + sizeof(struct ip));
+ m->m_len = sizeof(struct udpiphdr) + 1;
+ bzero(m_mtod(m), m->m_len);
+ m->m_pkthdr.len = m->m_len;
+
+ ip->ip_len = m->m_len;
+ ip->ip_ttl = ip_defttl;
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_src = ((struct sockaddr_in*)&sav->sah->saidx.src)->sin_addr;
+ ip->ip_dst = ((struct sockaddr_in*)&sav->sah->saidx.dst)->sin_addr;
+ uh->uh_sport = htons((u_short)esp_udp_encap_port);
+ uh->uh_dport = htons(sav->remote_ike_port);
+ uh->uh_ulen = htons(1 + sizeof(struct udphdr));
+ uh->uh_sum = 0;
+ *(u_int8_t*)((char*)m_mtod(m) + sizeof(struct ip) + sizeof(struct udphdr)) = 0xFF;
+
+ lck_mtx_unlock(sadb_mutex);
+ error = ip_output(m, NULL, &sav->sah->sa_route, IP_NOIPSEC, NULL);
+ lck_mtx_lock(sadb_mutex);
+ if (error == 0)
+ sav->natt_last_activity = natt_now;
+
+}