diff options
author | Niels Provos <provos@cvs.openbsd.org> | 1998-05-18 21:11:13 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 1998-05-18 21:11:13 +0000 |
commit | 0a99f14607ee1c61291cc2ef2b27e12fa8150b57 (patch) | |
tree | 16d9ebdb669b92f649893f48e323f5efe1f65f1c /sys/netinet/ip_output.c | |
parent | 32b196f4e8de3c9182f2326dab7a9409ca8e45ad (diff) |
first step to the setsockopt/getsockopt interface as described in
draft-mcdonald-simple-ipsec-api, kernel notifies (EMT_REQUESTSA) signal
userland key management applications when security services are requested.
this is only for outgoing connections at the moment, incoming packets
are not yet checked against the selected socket policy.
Diffstat (limited to 'sys/netinet/ip_output.c')
-rw-r--r-- | sys/netinet/ip_output.c | 76 |
1 files changed, 68 insertions, 8 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index d2283dd35c6..6f2a8534daf 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.26 1998/03/18 10:16:31 provos Exp $ */ +/* $OpenBSD: ip_output.c,v 1.27 1998/05/18 21:11:02 provos Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -45,6 +45,7 @@ #include <sys/socketvar.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/proc.h> #include <net/if.h> #include <net/route.h> @@ -68,6 +69,9 @@ #include <netinet/udp.h> #include <netinet/tcp.h> #include <sys/syslog.h> + +extern u_int8_t get_sa_require __P((struct inpcb *)); + #endif static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); @@ -77,6 +81,12 @@ static void ip_mloopback int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)); #endif +#ifdef IPSEC +extern int ipsec_auth_default_level; +extern int ipsec_esp_trans_default_level; +extern int ipsec_esp_network_default_level; +#endif + /* * IP output. The packet in mbuf chain m contains a skeletal IP * header (with len, off, ttl, proto, tos, src, dst). @@ -110,6 +120,7 @@ ip_output(m0, va_alist) struct udphdr *udp; struct tcphdr *tcp; struct expiration *exp; + struct inpcb *inp; #endif va_start(ap, m0); @@ -117,6 +128,9 @@ ip_output(m0, va_alist) ro = va_arg(ap, struct route *); flags = va_arg(ap, int); imo = va_arg(ap, struct ip_moptions *); +#ifdef IPSEC + inp = va_arg(ap, struct inpcb *); +#endif va_end(ap); @@ -147,13 +161,20 @@ ip_output(m0, va_alist) /* * Check if the packet needs encapsulation */ - if (!(flags & IP_ENCAPSULATED)) { - struct route_enc { - struct rtentry *re_rt; - struct sockaddr_encap re_dst; - } re0, *re = &re0; + if (!(flags & IP_ENCAPSULATED) && + (inp == NULL || + (inp->inp_seclevel[SL_AUTH] != IPSEC_LEVEL_BYPASS || + inp->inp_seclevel[SL_ESP_TRANS] != IPSEC_LEVEL_BYPASS || + inp->inp_seclevel[SL_ESP_NETWORK] != IPSEC_LEVEL_BYPASS))) { + struct route_enc re0, *re = &re0; struct sockaddr_encap *dst, *gw; struct tdb *tdb; + u_int8_t sa_require, sa_have = 0; + + if (inp == NULL) + sa_require = get_sa_require(inp); + else + sa_require = inp->inp_secrequire; bzero((caddr_t) re, sizeof(*re)); dst = (struct sockaddr_encap *) &re->re_dst; @@ -234,6 +255,15 @@ ip_output(m0, va_alist) tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, gw->sen_ipsp_dst, gw->sen_ipsp_sproto); + /* + * Now we check if this tdb has all the transforms which + * are requried by the socket or our default policy. + */ + SPI_CHAIN_ATTRIB(sa_have, tdb_onext, tdb); + + if (sa_require & ~sa_have) + goto no_encap; + #ifdef ENCDEBUG if (encdebug && (tdb == NULL)) printf("ip_output(): non-existant TDB for SA %08x/%x/%d\n", @@ -396,12 +426,17 @@ expbail: NTOHS(ip->ip_len); NTOHS(ip->ip_off); return ip_output(m, NULL, NULL, - IP_ENCAPSULATED | IP_RAWOUTPUT, NULL); + IP_ENCAPSULATED | IP_RAWOUTPUT, NULL, NULL); no_encap: /* This is for possible future use, don't move or delete */ if (re->re_rt) RTFREE(re->re_rt); + /* We did no IPSec encapsulation but the socket required it */ + if (sa_require) { + error = EHOSTUNREACH; + goto done; + } } #endif /* IPSEC */ @@ -795,6 +830,7 @@ ip_ctloutput(op, so, level, optname, mp) register struct inpcb *inp = sotoinpcb(so); register struct mbuf *m = *mp; register int optval = 0; + struct proc *p = curproc; /* XXX */ int error = 0; if (level != IPPROTO_IP) { @@ -898,24 +934,48 @@ ip_ctloutput(op, so, level, optname, mp) #ifndef IPSEC error = EINVAL; #else - if (m == 0 || m->m_len != sizeof(u_char)) { + if (m == 0 || m->m_len != sizeof(int)) { error = EINVAL; break; } optval = *mtod(m, u_char *); + + if (optval < IPSEC_LEVEL_BYPASS || + optval > IPSEC_LEVEL_UNIQUE) { + error = EINVAL; + break; + } + switch (optname) { case IP_AUTH_LEVEL: + if (optval < ipsec_auth_default_level && + suser(p->p_ucred, &p->p_acflag)) { + error = EACCES; + break; + } inp->inp_seclevel[SL_AUTH] = optval; break; case IP_ESP_TRANS_LEVEL: + if (optval < ipsec_esp_trans_default_level && + suser(p->p_ucred, &p->p_acflag)) { + error = EACCES; + break; + } inp->inp_seclevel[SL_ESP_TRANS] = optval; break; case IP_ESP_NETWORK_LEVEL: + if (optval < ipsec_esp_network_default_level && + suser(p->p_ucred, &p->p_acflag)) { + error = EACCES; + break; + } inp->inp_seclevel[SL_ESP_NETWORK] = optval; break; } + if (!error) + inp->inp_secrequire = get_sa_require(inp); #endif break; |