diff options
author | Niels Provos <provos@cvs.openbsd.org> | 1999-03-27 21:04:22 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 1999-03-27 21:04:22 +0000 |
commit | defd96f785a6fc79d07307a2e69e27c048f432af (patch) | |
tree | 22a5f004782330ad329e92ec854e4f9bb9d51b5c /sys/netinet | |
parent | bdf0fa84baff8b71398e2760eb959d794df83839 (diff) |
add SADB_X_BINDSA to pfkey allowing incoming SAs to refer to an outgoing
SA to be used, use this SA in ip_output if available. allow mobile road
warriors for bind SAs with wildcard dst and src addresses. check IPSEC
AUTH and ESP level when receiving packets, drop them if protection is
insufficient. add stats to show dropped packets because of insufficient
IPSEC protection. -- phew. this was all done in canada. dugsong and linh
provided the ride and company.
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/in.h | 4 | ||||
-rw-r--r-- | sys/netinet/in_pcb.c | 4 | ||||
-rw-r--r-- | sys/netinet/in_pcb.h | 5 | ||||
-rw-r--r-- | sys/netinet/ip_ah.c | 30 | ||||
-rw-r--r-- | sys/netinet/ip_esp.c | 30 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.c | 149 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.h | 15 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 85 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 52 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 3 | ||||
-rw-r--r-- | sys/netinet/udp_usrreq.c | 39 | ||||
-rw-r--r-- | sys/netinet/udp_var.h | 3 |
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: */ |