summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/in.h4
-rw-r--r--sys/netinet/in_pcb.c4
-rw-r--r--sys/netinet/in_pcb.h5
-rw-r--r--sys/netinet/ip_ah.c30
-rw-r--r--sys/netinet/ip_esp.c30
-rw-r--r--sys/netinet/ip_ipsp.c149
-rw-r--r--sys/netinet/ip_ipsp.h15
-rw-r--r--sys/netinet/ip_output.c85
-rw-r--r--sys/netinet/tcp_input.c52
-rw-r--r--sys/netinet/tcp_var.h3
-rw-r--r--sys/netinet/udp_usrreq.c39
-rw-r--r--sys/netinet/udp_var.h3
12 files changed, 353 insertions, 66 deletions
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index 38bd73db826..d58c46f1bc5 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.h,v 1.20 1999/03/24 02:31:03 cmetz Exp $ */
+/* $OpenBSD: in.h,v 1.21 1999/03/27 21:04:21 provos Exp $ */
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
/*
@@ -379,6 +379,8 @@ struct ip_opts {
#define ICMPV6_FILTER 38 /* struct icmpv6_filter; get/set filter */
#define ICMP6_FILTER ICMP6_FILTER
+#define IPSEC_OUTSA 39 /* set the outbound SA for a socket */
+
/*
* Security levels - IPsec, not IPSO
*/
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 23c656d635b..66fc00db939 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.c,v 1.31 1999/03/24 02:28:21 cmetz Exp $ */
+/* $OpenBSD: in_pcb.c,v 1.32 1999/03/27 21:04:18 provos Exp $ */
/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
/*
@@ -529,6 +529,8 @@ in_pcbdetach(v)
ip_freemoptions(inp->inp_moptions);
#ifdef IPSEC
/* XXX IPsec cleanup here */
+ if (inp->inp_tdb)
+ TAILQ_REMOVE(&inp->inp_tdb->tdb_inp, inp, inp_tdb_next);
#endif
s = splnet();
LIST_REMOVE(inp, inp_hash);
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 176ce07a742..cb753c3ae82 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.h,v 1.16 1999/03/24 02:33:02 cmetz Exp $ */
+/* $OpenBSD: in_pcb.h,v 1.17 1999/03/27 21:04:19 provos Exp $ */
/* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */
/*
@@ -40,6 +40,7 @@
#include <netinet6/ipv6.h>
#include <netinet6/ipv6_var.h>
#include <netinet6/icmpv6.h>
+#include <netinet/ip_ipsp.h>
union inpaddru {
struct in6_addr iau_addr6;
@@ -99,6 +100,8 @@ struct inpcb {
#define SR_FAILED 1 /* Negotiation failed permanently */
#define SR_SUCCESS 2 /* SA successfully established */
#define SR_WAIT 3 /* Waiting for SA */
+ TAILQ_ENTRY(inpcb) inp_tdb_next;
+ struct tdb *inp_tdb; /* If tdb_dst matches our dst, use */
int inp_fflowinfo; /* Foreign flowlabel & priority */
int inp_csumoffset;
struct icmpv6_filter inp_filter;
diff --git a/sys/netinet/ip_ah.c b/sys/netinet/ip_ah.c
index afa4cbe472b..4fdb5d29813 100644
--- a/sys/netinet/ip_ah.c
+++ b/sys/netinet/ip_ah.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ah.c,v 1.18 1999/02/24 23:45:46 angelos Exp $ */
+/* $OpenBSD: ip_ah.c,v 1.19 1999/03/27 21:04:19 provos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -238,6 +238,32 @@ ah_input(register struct mbuf *m, int iphlen)
return;
}
+ if (ipo->ip_p == IPPROTO_TCP || ipo->ip_p == IPPROTO_UDP)
+ {
+ struct tdb_ident *tdbi = NULL;
+ if (tdbp->tdb_bind_out)
+ {
+ tdbi = m->m_pkthdr.tdbi;
+ if (!(m->m_flags & M_PKTHDR))
+ {
+ DPRINTF(("ah_input(): mbuf is not a packet header!\n"));
+ }
+ if (!tdbi || !(m->m_flags & (M_CONF|M_AUTH)))
+ MALLOC(tdbi, struct tdb_ident *, sizeof(struct tdb_ident),
+ M_TEMP, M_NOWAIT);
+
+ if (!tdbi)
+ goto no_mem;
+
+ tdbi->spi = tdbp->tdb_bind_out->tdb_spi;
+ tdbi->dst = tdbp->tdb_bind_out->tdb_dst;
+ tdbi->proto = tdbp->tdb_bind_out->tdb_sproto;
+ }
+
+ m->m_pkthdr.tdbi = tdbi;
+ no_mem:
+ }
+
/* Packet is authentic */
m->m_flags |= M_AUTH;
@@ -277,6 +303,8 @@ ah_input(register struct mbuf *m, int iphlen)
if (IF_QFULL(ifq))
{
IF_DROP(ifq);
+ if (m->m_pkthdr.tdbi)
+ free(m->m_pkthdr.tdbi, M_TEMP);
m_freem(m);
ahstat.ahs_qfull++;
splx(s);
diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c
index f2da8435264..b099bdd1579 100644
--- a/sys/netinet/ip_esp.c
+++ b/sys/netinet/ip_esp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_esp.c,v 1.18 1999/02/24 23:45:49 angelos Exp $ */
+/* $OpenBSD: ip_esp.c,v 1.19 1999/03/27 21:04:19 provos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -237,6 +237,32 @@ esp_input(register struct mbuf *m, int iphlen)
return;
}
+ if (ipo->ip_p == IPPROTO_TCP || ipo->ip_p == IPPROTO_UDP)
+ {
+ struct tdb_ident *tdbi = NULL;
+ if (tdbp->tdb_bind_out)
+ {
+ tdbi = m->m_pkthdr.tdbi;
+ if (!(m->m_flags & M_PKTHDR))
+ {
+ DPRINTF(("esp_input(): mbuf is not a packet header!\n"));
+ }
+ if (!tdbi || !(m->m_flags & (M_CONF|M_AUTH)))
+ MALLOC(tdbi, struct tdb_ident *, sizeof(struct tdb_ident),
+ M_TEMP, M_NOWAIT);
+
+ if (!tdbi)
+ goto no_mem;
+
+ tdbi->spi = tdbp->tdb_bind_out->tdb_spi;
+ tdbi->dst = tdbp->tdb_bind_out->tdb_dst;
+ tdbi->proto = tdbp->tdb_bind_out->tdb_sproto;
+ }
+
+ m->m_pkthdr.tdbi = tdbi;
+ no_mem:
+ }
+
/* Packet is confidental */
m->m_flags |= M_CONF;
@@ -276,6 +302,8 @@ esp_input(register struct mbuf *m, int iphlen)
if (IF_QFULL(ifq))
{
IF_DROP(ifq);
+ if (m->m_pkthdr.tdbi)
+ free(m->m_pkthdr.tdbi, M_TEMP);
m_freem(m);
espstat.esps_qfull++;
splx(s);
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c
index 21ba455bca3..a6eef7e135a 100644
--- a/sys/netinet/ip_ipsp.c
+++ b/sys/netinet/ip_ipsp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.c,v 1.38 1999/03/24 17:00:47 niklas Exp $ */
+/* $OpenBSD: ip_ipsp.c,v 1.39 1999/03/27 21:04:19 provos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -184,6 +184,7 @@ check_ipsec_policy(struct inpcb *inp, u_int32_t daddr)
struct sockaddr_encap *dst;
u_int8_t sa_require, sa_have;
int error, i;
+ struct tdb *tdb = NULL;
if (inp == NULL || ((so = inp->inp_socket) == 0))
return (EINVAL);
@@ -191,59 +192,60 @@ check_ipsec_policy(struct inpcb *inp, u_int32_t daddr)
/* If IPSEC is not required just use what we got */
if (!(sa_require = inp->inp_secrequire))
return 0;
-
- bzero((caddr_t) re, sizeof(*re));
- dst = (struct sockaddr_encap *) &re->re_dst;
- dst->sen_family = PF_KEY;
- dst->sen_len = SENT_IP4_LEN;
- dst->sen_type = SENT_IP4;
- dst->sen_ip_src = inp->inp_laddr;
- dst->sen_ip_dst.s_addr = inp->inp_faddr.s_addr ?
- inp->inp_faddr.s_addr : daddr;
- dst->sen_proto = so->so_proto->pr_protocol;
- switch (dst->sen_proto)
+
+ if (!inp->inp_tdb)
{
- case IPPROTO_UDP:
- case IPPROTO_TCP:
+ bzero((caddr_t) re, sizeof(*re));
+ dst = (struct sockaddr_encap *) &re->re_dst;
+ dst->sen_family = PF_KEY;
+ dst->sen_len = SENT_IP4_LEN;
+ dst->sen_type = SENT_IP4;
+ dst->sen_ip_src = inp->inp_laddr;
+ dst->sen_ip_dst.s_addr = inp->inp_faddr.s_addr ?
+ inp->inp_faddr.s_addr : daddr;
+ dst->sen_proto = so->so_proto->pr_protocol;
+ switch (dst->sen_proto)
+ {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
dst->sen_sport = inp->inp_lport;
dst->sen_dport = inp->inp_fport;
break;
- default:
+ default:
dst->sen_sport = 0;
dst->sen_dport = 0;
- }
+ }
- /* Try to find a flow */
- rtalloc((struct route *) re);
+ /* Try to find a flow */
+ rtalloc((struct route *) re);
- if (re->re_rt != NULL)
- {
- struct tdb *tdb;
- struct sockaddr_encap *gw;
-
- gw = (struct sockaddr_encap *) (re->re_rt->rt_gateway);
-
- if (gw->sen_type == SENT_IPSP) {
- sunion.sin.sin_family = AF_INET;
- sunion.sin.sin_len = sizeof(struct sockaddr_in);
- sunion.sin.sin_addr = gw->sen_ipsp_dst;
+ if (re->re_rt != NULL)
+ {
+ struct sockaddr_encap *gw;
- tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, &sunion,
- gw->sen_ipsp_sproto);
-
- SPI_CHAIN_ATTRIB(sa_have, tdb_onext, tdb);
+ gw = (struct sockaddr_encap *) (re->re_rt->rt_gateway);
+
+ if (gw->sen_type == SENT_IPSP) {
+ sunion.sin.sin_family = AF_INET;
+ sunion.sin.sin_len = sizeof(struct sockaddr_in);
+ sunion.sin.sin_addr = gw->sen_ipsp_dst;
+
+ tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, &sunion,
+ gw->sen_ipsp_sproto);
+ }
+ RTFREE(re->re_rt);
}
- else
- sa_have = 0;
-
- RTFREE(re->re_rt);
-
- /* Check if our requirements are met */
- if (!(sa_require & ~sa_have))
- return 0;
- }
- else
- sa_have = 0;
+ } else
+ tdb = inp->inp_tdb;
+
+ if (tdb) {
+ SPI_CHAIN_ATTRIB(sa_have, tdb_onext, tdb);
+ } else
+ sa_have = 0;
+
+ /* Check if our requirements are met */
+ if (!(sa_require & ~sa_have))
+ return 0;
error = i = 0;
@@ -290,6 +292,24 @@ check_ipsec_policy(struct inpcb *inp, u_int32_t daddr)
}
/*
+ * Add an inpcb to the list of inpcb which reference this tdb directly.
+ */
+
+void
+tdb_add_inp(struct tdb *tdb, struct inpcb *inp)
+{
+ if (inp->inp_tdb) {
+ if (inp->inp_tdb == tdb)
+ return;
+ TAILQ_REMOVE(&inp->inp_tdb->tdb_inp, inp, inp_tdb_next);
+ }
+ inp->inp_tdb = tdb;
+ TAILQ_INSERT_TAIL(&tdb->tdb_inp, inp, inp_tdb_next);
+
+ DPRINTF(("tdb_add_inp: tdb: %p, inp: %p\n", tdb, inp));
+}
+
+/*
* Reserve an SPI; the SA is not valid yet though. Zero is reserved as
* an error return value. If tspi is not zero, we try to allocate that
* SPI.
@@ -659,6 +679,7 @@ tdb_delete(struct tdb *tdbp, int delchain)
{
u_int8_t *ptr = (u_int8_t *) &tdbp->tdb_dst;
struct tdb *tdbpp;
+ struct inpcb *inp;
u_int32_t hashval = tdbp->tdb_sproto + tdbp->tdb_spi, i;
for (i = 0; i < SA_LEN(&tdbp->tdb_dst.sa); i++)
@@ -706,6 +727,24 @@ tdb_delete(struct tdb *tdbp, int delchain)
ipsec_in_use--;
}
+ /* Cleanup SA-Bindings */
+ for (tdbpp = TAILQ_FIRST(&tdbp->tdb_bind_in); tdbpp;
+ tdbpp = TAILQ_FIRST(&tdbp->tdb_bind_in))
+ {
+ TAILQ_REMOVE(&tdbpp->tdb_bind_in, tdbpp, tdb_bind_in_next);
+ tdbpp->tdb_bind_out = NULL;
+ }
+ /* Cleanup inp references */
+ for (inp = TAILQ_FIRST(&tdbp->tdb_inp); inp;
+ inp = TAILQ_FIRST(&tdbp->tdb_inp))
+ {
+ TAILQ_REMOVE(&tdbp->tdb_inp, inp, inp_tdb_next);
+ inp->inp_tdb = NULL;
+ }
+
+ if (tdbp->tdb_bind_out)
+ TAILQ_REMOVE(&tdbp->tdb_bind_out->tdb_bind_in, tdbp, tdb_bind_in_next);
+
/* removal of a larval SA should not remove the mature SA's expirations */
if ((tdbp->tdb_flags & TDBF_INVALID) == 0)
cleanup_expirations(&tdbp->tdb_dst, tdbp->tdb_spi, tdbp->tdb_sproto);
@@ -733,6 +772,10 @@ tdb_init(struct tdb *tdbp, u_int16_t alg, struct ipsecinit *ii)
tdbp->tdb_established = time.tv_sec;
tdbp->tdb_epoch = kernfs_epoch - 1;
+ /* Init Incoming SA-Binding Queues */
+ TAILQ_INIT(&tdbp->tdb_bind_in);
+ TAILQ_INIT(&tdbp->tdb_inp);
+
for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++)
if (xsp->xf_type == alg)
return (*(xsp->xf_init))(tdbp, xsp, ii);
@@ -752,7 +795,7 @@ ipsp_kern(int off, char **bufp, int len)
{
static char buffer[IPSEC_KERNFS_BUFSIZE];
struct flow *flow;
- struct tdb *tdb;
+ struct tdb *tdb, *tdbp;
int l, i;
if (off == 0)
@@ -866,6 +909,22 @@ ipsp_kern(int off, char **bufp, int len)
l += sprintf(buffer + l, "\t\tAuthentication = <%s>\n",
tdb->tdb_authalgxform->name);
+ if (tdb->tdb_bind_out)
+ l += sprintf(buffer + l,
+ "\tBound SA: SPI = %08x, "
+ "Destination = %s, Sproto = %u\n",
+ ntohl(tdb->tdb_bind_out->tdb_spi),
+ ipsp_address(tdb->tdb_bind_out->tdb_dst),
+ tdb->tdb_bind_out->tdb_sproto);
+ for (i = 0, tdbp = TAILQ_FIRST(&tdb->tdb_bind_in); tdbp;
+ tdbp = TAILQ_NEXT(tdbp, tdb_bind_in_next))
+ i++;
+
+ if (i > 0)
+ l += sprintf(buffer + l,
+ "\tReferenced by %d incoming SA%s\n",
+ i, i == 1 ? "" : "s");
+
if (tdb->tdb_onext)
l += sprintf(buffer + l,
"\tNext SA: SPI = %08x, "
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
index f0048366b3c..e963410849f 100644
--- a/sys/netinet/ip_ipsp.h
+++ b/sys/netinet/ip_ipsp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.h,v 1.27 1999/02/25 01:30:49 angelos Exp $ */
+/* $OpenBSD: ip_ipsp.h,v 1.28 1999/03/27 21:04:19 provos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -43,6 +43,7 @@
*/
#include <sys/types.h>
+#include <sys/queue.h>
#include <netinet/in.h>
#include <sys/md5k.h>
#include <netinet/ip_sha1.h>
@@ -283,10 +284,21 @@ struct tdb /* tunnel descriptor block */
u_int16_t tdb_dstid_type;
struct flow *tdb_flow; /* Which flows use this SA */
+
+ struct tdb *tdb_bind_out; /* Outgoing SA to use */
+ TAILQ_HEAD(tdb_bind_head, tdb) tdb_bind_in;
+ TAILQ_ENTRY(tdb) tdb_bind_in_next; /* Refering Incoming SAs */
+ TAILQ_HEAD(tdb_inp_head, inpcb) tdb_inp;
};
#define TDB_HASHMOD 257
+struct tdb_ident {
+ u_int32_t spi;
+ union sockaddr_union dst;
+ u_int8_t proto;
+};
+
struct auth_hash {
int type;
char *name;
@@ -418,6 +430,7 @@ extern char *inet_ntoa4(struct in_addr);
extern char *ipsp_address(union sockaddr_union);
/* TDB management routines */
+extern void tdb_add_inp(struct tdb *tdb, struct inpcb *inp);
extern u_int32_t reserve_spi(u_int32_t, u_int32_t, union sockaddr_union *,
union sockaddr_union *, u_int8_t, int *);
extern struct tdb *gettdb(u_int32_t, union sockaddr_union *, u_int8_t);
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 311806ea3d8..0c0400c0c1a 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.43 1999/03/24 17:00:47 niklas Exp $ */
+/* $OpenBSD: ip_output.c,v 1.44 1999/03/27 21:04:20 provos Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -167,8 +167,7 @@ ip_output(m0, va_alist)
/*
* Check if the packet needs encapsulation
*/
- if ((ipsec_in_use != 0) &&
- !(flags & IP_ENCAPSULATED) &&
+ if (!(flags & IP_ENCAPSULATED) &&
(inp == NULL ||
(inp->inp_seclevel[SL_AUTH] != IPSEC_LEVEL_BYPASS ||
inp->inp_seclevel[SL_ESP_TRANS] != IPSEC_LEVEL_BYPASS ||
@@ -184,6 +183,20 @@ ip_output(m0, va_alist)
sa_require = inp->inp_secrequire;
bzero((caddr_t) re, sizeof(*re));
+
+ /* Check if there was a bound outgoing SA */
+ if (inp && inp->inp_tdb &&
+ (inp->inp_tdb->tdb_dst.sin.sin_addr.s_addr ==
+ INADDR_ANY ||
+ !bcmp(&inp->inp_tdb->tdb_dst.sin.sin_addr,
+ &ip->ip_dst, sizeof(ip->ip_dst)))) {
+ tdb = inp->inp_tdb;
+ goto have_tdb;
+ }
+
+ if (!ipsec_in_use)
+ goto no_encap;
+
ddst = (struct sockaddr_encap *) &re->re_dst;
ddst->sen_family = PF_KEY;
ddst->sen_len = SENT_IP4_LEN;
@@ -266,10 +279,6 @@ ip_output(m0, va_alist)
goto no_encap;
}
- ip->ip_len = htons((u_short)ip->ip_len);
- ip->ip_off = htons((u_short)ip->ip_off);
- ip->ip_sum = 0;
-
/*
* At this point we have an IPSP "gateway" (tunnel) spec.
* Use the destination of the tunnel and the SPI to
@@ -284,6 +293,12 @@ ip_output(m0, va_alist)
tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, &sunion,
gw->sen_ipsp_sproto);
+ have_tdb:
+
+ ip->ip_len = htons((u_short)ip->ip_len);
+ ip->ip_off = htons((u_short)ip->ip_off);
+ ip->ip_sum = 0;
+
/*
* Now we check if this tdb has all the transforms which
* are requried by the socket or our default policy.
@@ -354,7 +369,8 @@ ip_output(m0, va_alist)
if (tdb->tdb_flags & TDBF_INVALID) {
DPRINTF(("ip_output(): attempt to use invalid SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto));
m_freem(m);
- RTFREE(re->re_rt);
+ if (re->re_rt)
+ RTFREE(re->re_rt);
return ENXIO;
}
@@ -389,6 +405,8 @@ ip_output(m0, va_alist)
/* Check for tunneling */
if (((tdb->tdb_dst.sin.sin_addr.s_addr !=
+ INADDR_ANY &&
+ tdb->tdb_dst.sin.sin_addr.s_addr !=
ip->ip_dst.s_addr) ||
(tdb->tdb_flags & TDBF_TUNNELING)) &&
(tdb->tdb_xform->xf_type != XF_IP4))
@@ -404,7 +422,8 @@ ip_output(m0, va_alist)
if (mp == NULL)
error = EFAULT;
if (error) {
- RTFREE(re->re_rt);
+ if (re->re_rt)
+ RTFREE(re->re_rt);
return error;
}
m = mp;
@@ -427,7 +446,8 @@ ip_output(m0, va_alist)
if (error) {
if (mp != NULL)
m_freem(mp);
- RTFREE(re->re_rt);
+ if (re->re_rt)
+ RTFREE(re->re_rt);
return error;
}
@@ -444,7 +464,8 @@ ip_output(m0, va_alist)
* processed packet. Call ourselves recursively, but
* bypass the encap code.
*/
- RTFREE(re->re_rt);
+ if (re->re_rt)
+ RTFREE(re->re_rt);
ip = mtod(m, struct ip *);
NTOHS(ip->ip_len);
NTOHS(ip->ip_off);
@@ -953,6 +974,28 @@ ip_ctloutput(op, so, level, optname, mp)
}
}
break;
+ case IPSEC_OUTSA:
+#ifndef IPSEC
+ error = EINVAL;
+#else
+ if (m == 0 || m->m_len != sizeof(struct tdb_ident)) {
+ error = EINVAL;
+ break;
+ } else {
+ struct tdb *tdb;
+ struct tdb_ident *tdbi;
+
+ tdbi = mtod(m, struct tdb_ident *);
+ tdb = gettdb(tdbi->spi, &tdbi->dst,
+ tdbi->proto);
+ if (tdb == NULL) {
+ error = ESRCH;
+ break;
+ }
+ tdb_add_inp(tdb, inp);
+ }
+#endif /* IPSEC */
+ break;
case IP_AUTH_LEVEL:
case IP_ESP_TRANS_LEVEL:
@@ -1082,6 +1125,26 @@ ip_ctloutput(op, so, level, optname, mp)
*mtod(m, int *) = optval;
break;
+ case IPSEC_OUTSA:
+#ifndef IPSEC
+ error = EINVAL;
+#else
+ if (inp->inp_tdb == NULL) {
+ error = ENOENT;
+ break;
+ } else {
+ struct tdb_ident tdbi;
+ tdbi.spi = inp->inp_tdb->tdb_spi;
+ tdbi.dst = inp->inp_tdb->tdb_dst;
+ tdbi.proto = inp->inp_tdb->tdb_sproto;
+ *mp = m = m_get(M_WAIT, MT_SOOPTS);
+ m->m_len = sizeof(tdbi);
+ bcopy((caddr_t)&tdbi, mtod(m, caddr_t),
+ (unsigned)m->m_len);
+ }
+#endif /* IPSEC */
+ break;
+
case IP_AUTH_LEVEL:
case IP_ESP_TRANS_LEVEL:
case IP_ESP_NETWORK_LEVEL:
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 1bb0da1d16e..59086ee521b 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.32 1999/02/15 02:39:02 provos Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.33 1999/03/27 21:04:20 provos Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -77,6 +77,10 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <machine/stdarg.h>
#include <sys/md5k.h>
+#ifdef IPSEC
+#include <netinet/ip_ipsp.h>
+#endif /* IPSEC */
+
#ifdef INET6
#include <sys/domain.h>
#include <netinet6/in6_var.h>
@@ -437,6 +441,9 @@ tcp_input(m, va_alist)
int iphlen;
va_list ap;
register struct tcphdr *th;
+#ifdef IPSEC
+ struct tdb *tdb = NULL;
+#endif /* IPSEC */
#ifdef INET6
struct in6_addr laddr6;
unsigned short is_ipv6; /* Type of incoming datagram. */
@@ -449,6 +456,15 @@ tcp_input(m, va_alist)
tcpstat.tcps_rcvtotal++;
+#ifdef IPSEC
+ /* Save the last SA which was used to process the mbuf */
+ if ((m->m_flags & (M_CONF|M_AUTH)) && m->m_pkthdr.tdbi) {
+ struct tdb_ident *tdbi = m->m_pkthdr.tdbi;
+ tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
+ free(m->m_pkthdr.tdbi, M_TEMP);
+ m->m_pkthdr.tdbi = NULL;
+ }
+#endif /* IPSEC */
#ifdef INET6
/*
* Before we do ANYTHING, we have to figure out if it's TCP/IPv6 or
@@ -683,6 +699,18 @@ findpcb:
* we're committed to it below in TCPS_LISTEN.
*/
dropsocket++;
+#ifdef IPSEC
+ /*
+ * We need to copy the required security levels
+ * from the old pcb.
+ */
+ {
+ struct inpcb *newinp = (struct inpcb *)so->so_pcb;
+ bcopy(inp->inp_seclevel, newinp->inp_seclevel,
+ sizeof(inp->inp_seclevel));
+ newinp->inp_secrequire = inp->inp_secrequire;
+ }
+#endif /* IPSEC */
#ifdef INET6
/*
* inp still has the OLD in_pcb stuff, set the
@@ -748,6 +776,28 @@ findpcb:
}
}
+#ifdef IPSEC
+ /* Check if this socket requires security for incoming packets */
+ if ((inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_REQUIRE &&
+ !(m->m_flags & M_AUTH)) ||
+ (inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE &&
+ !(m->m_flags & M_CONF))) {
+#ifdef notyet
+#ifdef INET6
+ if (is_ipv6)
+ ipv6_icmp_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);
+ else
+#endif /* INET6 */
+ icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);
+#endif /* notyet */
+ tcpstat.tcps_rcvnosec++;
+ goto drop;
+ }
+ /* Use tdb_bind_out for this inp's outbound communication */
+ if (tdb)
+ tdb_add_inp(tdb, inp);
+#endif /*IPSEC */
+
/*
* Segment received on connection.
* Reset idle time and keep-alive timer.
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index c4c1b2213ec..f7ac9a841b3 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_var.h,v 1.18 1999/02/04 16:12:13 deraadt Exp $ */
+/* $OpenBSD: tcp_var.h,v 1.19 1999/03/27 21:04:21 provos Exp $ */
/* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */
/*
@@ -244,6 +244,7 @@ struct tcpstat {
u_int32_t tcps_rcvbadsum; /* packets received with ccksum errs */
u_int32_t tcps_rcvbadoff; /* packets received with bad offset */
u_int32_t tcps_rcvmemdrop; /* packets dropped for lack of memory */
+ u_int32_t tcps_rcvnosec; /* packets dropped for lack of ipsec */
u_int32_t tcps_rcvshort; /* packets received too short */
u_int32_t tcps_rcvduppack; /* duplicate-only packets received */
u_int64_t tcps_rcvdupbyte; /* duplicate-only bytes received */
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 48805a76134..ce04a080ad8 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_usrreq.c,v 1.24 1999/03/24 02:59:06 cmetz Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.25 1999/03/27 21:04:20 provos Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
@@ -76,6 +76,8 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <netinet/udp_var.h>
#ifdef IPSEC
+#include <netinet/ip_ipsp.h>
+
extern int check_ipsec_policy __P((struct inpcb *, u_int32_t));
#endif
@@ -147,6 +149,9 @@ udp_input(m, va_alist)
struct ipv6 *ipv6;
struct sockaddr_in6 src_v4mapped;
#endif /* INET6 */
+#ifdef IPSEC
+ struct tdb *tdb = NULL;
+#endif /* IPSEC */
va_start(ap, m);
iphlen = va_arg(ap, int);
@@ -154,6 +159,16 @@ udp_input(m, va_alist)
udpstat.udps_ipackets++;
+#ifdef IPSEC
+ /* Save the last SA which was used to process the mbuf */
+ if ((m->m_flags & (M_CONF|M_AUTH)) && m->m_pkthdr.tdbi) {
+ struct tdb_ident *tdbi = m->m_pkthdr.tdbi;
+ tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
+ free(m->m_pkthdr.tdbi, M_TEMP);
+ m->m_pkthdr.tdbi = NULL;
+ }
+#endif /* IPSEC */
+
switch (mtod(m, struct ip *)->ip_v) {
case 4:
ip = mtod(m, struct ip *);
@@ -485,6 +500,28 @@ udp_input(m, va_alist)
}
}
+#ifdef IPSEC
+ /* Check if this socket requires security for incoming packets */
+ if ((inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_REQUIRE &&
+ !(m->m_flags & M_AUTH)) ||
+ (inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE &&
+ !(m->m_flags & M_CONF))) {
+#ifdef notyet
+#ifdef INET6
+ if (ipv6)
+ ipv6_icmp_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);
+ else
+#endif /* INET6 */
+ icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);
+#endif /* notyet */
+ udpstat.udps_nosec++;
+ goto bad;
+ }
+ /* Use tdb_bind_out for this inp's outbound communication */
+ if (tdb)
+ tdb_add_inp(tdb, inp);
+#endif /*IPSEC */
+
if (inp->inp_flags & INP_CONTROLOPTS) {
struct mbuf **mp = &opts;
diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h
index f41b8aa10b5..afc23036d32 100644
--- a/sys/netinet/udp_var.h
+++ b/sys/netinet/udp_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_var.h,v 1.7 1999/02/04 16:05:02 deraadt Exp $ */
+/* $OpenBSD: udp_var.h,v 1.8 1999/03/27 21:04:21 provos Exp $ */
/* $NetBSD: udp_var.h,v 1.12 1996/02/13 23:44:41 christos Exp $ */
/*
@@ -62,6 +62,7 @@ struct udpstat {
u_long udps_badlen; /* data length larger than packet */
u_long udps_noport; /* no socket on port */
u_long udps_noportbcast; /* of above, arrived as broadcast */
+ u_long udps_nosec; /* dropped for lack of ipsec */
u_long udps_fullsock; /* not delivered, input socket full */
u_long udps_pcbhashmiss; /* input packets missing pcb hash */
/* output statistics: */