summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2012-07-16 18:05:37 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2012-07-16 18:05:37 +0000
commitc1c071f56546d75090dad47c26f4b82cf1c4db31 (patch)
tree9dc5da863568ebde526eef4650292746c9c86155 /sys
parentf298cc988d97280917f4b9ff77d0db5501c66744 (diff)
add IP_IPSECFLOWINFO option to sendmsg() and recvmsg(), so npppd(4)
can use this to select the IPsec tunnel for sending L2TP packets. this fixes Windows (always binding to 1701) and Android clients (negotiating wildcard flows); feedback mpf@ and yasuoka@; ok henning@ and yasuoka@; ok jmc@ for the manpage
Diffstat (limited to 'sys')
-rw-r--r--sys/net/if_bridge.c4
-rw-r--r--sys/netinet/in.h3
-rw-r--r--sys/netinet/in_pcb.h3
-rw-r--r--sys/netinet/ip_input.c6
-rw-r--r--sys/netinet/ip_ipsp.h4
-rw-r--r--sys/netinet/ip_output.c14
-rw-r--r--sys/netinet/ip_spd.c26
-rw-r--r--sys/netinet/ip_var.h3
-rw-r--r--sys/netinet/tcp_input.c4
-rw-r--r--sys/netinet/udp_usrreq.c60
-rw-r--r--sys/netinet6/ip6_forward.c4
-rw-r--r--sys/netinet6/ip6_output.c4
12 files changed, 108 insertions, 27 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index 730c902ab80..1d81886b002 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.c,v 1.193 2011/07/04 06:54:49 claudio Exp $ */
+/* $OpenBSD: if_bridge.c,v 1.194 2012/07/16 18:05:36 markus Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -2442,7 +2442,7 @@ bridge_ipsec(struct bridge_softc *sc, struct ifnet *ifp,
}
} else { /* Outgoing from the bridge. */
tdb = ipsp_spd_lookup(m, af, hlen, &error,
- IPSP_DIRECTION_OUT, NULL, NULL);
+ IPSP_DIRECTION_OUT, NULL, NULL, 0);
if (tdb != NULL) {
/*
* We don't need to do loop detection, the
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index 18f275bb84d..56e3986185a 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.h,v 1.92 2012/07/10 11:49:42 guenther Exp $ */
+/* $OpenBSD: in.h,v 1.93 2012/07/16 18:05:36 markus Exp $ */
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
/*
@@ -298,6 +298,7 @@ struct ip_opts {
#define IP_RECVDSTPORT 33 /* bool; receive IP dst port w/dgram */
#define IP_PIPEX 34 /* bool; using PIPEX */
#define IP_RECVRTABLE 35 /* bool; receive rdomain w/dgram */
+#define IP_IPSECFLOWINFO 36 /* bool; IPsec flow info for dgram */
#define IP_RTABLE 0x1021 /* int; routing table, see SO_RTABLE */
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index de634b82b7f..9d4f0d96c91 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.h,v 1.71 2011/06/15 09:11:01 mikeb Exp $ */
+/* $OpenBSD: in_pcb.h,v 1.72 2012/07/16 18:05:36 markus Exp $ */
/* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */
/*
@@ -175,6 +175,7 @@ struct inpcbtable {
#define INP_RECVTTL 0x040 /* receive incoming IP TTL */
#define INP_RECVDSTPORT 0x200 /* receive IP dst addr before rdr */
#define INP_RECVRTABLE 0x400 /* receive routing table */
+#define INP_IPSECFLOWINFO 0x800 /* receive IPsec flow info */
#define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR| \
INP_RXSRCRT|INP_HOPLIMIT|INP_RECVIF|INP_RECVTTL|INP_RECVDSTPORT| \
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 7fa3d66f7f0..b39dc35c4f0 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_input.c,v 1.195 2011/07/06 02:42:28 henning Exp $ */
+/* $OpenBSD: ip_input.c,v 1.196 2012/07/16 18:05:36 markus Exp $ */
/* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */
/*
@@ -479,7 +479,7 @@ ipv4_input(struct mbuf *m)
} else
tdb = NULL;
ipsp_spd_lookup(m, AF_INET, hlen, &error,
- IPSP_DIRECTION_IN, tdb, NULL);
+ IPSP_DIRECTION_IN, tdb, NULL, 0);
splx(s);
/* Error or otherwise drop-packet indication */
@@ -639,7 +639,7 @@ found:
} else
tdb = NULL;
ipsp_spd_lookup(m, AF_INET, hlen, &error, IPSP_DIRECTION_IN,
- tdb, NULL);
+ tdb, NULL, 0);
splx(s);
/* Error or otherwise drop-packet indication. */
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
index 80df24988d1..83b112262e6 100644
--- a/sys/netinet/ip_ipsp.h
+++ b/sys/netinet/ip_ipsp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.h,v 1.147 2012/06/29 14:48:04 mikeb Exp $ */
+/* $OpenBSD: ip_ipsp.h,v 1.148 2012/07/16 18:05:36 markus Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr),
@@ -634,7 +634,7 @@ extern unsigned char ipseczeroes[];
extern int ipsp_process_packet(struct mbuf *, struct tdb *, int, int);
extern int ipsp_process_done(struct mbuf *, struct tdb *);
extern struct tdb *ipsp_spd_lookup(struct mbuf *, int, int, int *, int,
- struct tdb *, struct inpcb *);
+ struct tdb *, struct inpcb *, u_int32_t);
extern struct tdb *ipsp_spd_inp(struct mbuf *, int, int, int *, int,
struct tdb *, struct inpcb *, struct ipsec_policy *);
extern int ipsec_common_input(struct mbuf *, int, int, int, int, int);
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 19acb1c7b64..83c61ea159e 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.229 2012/04/13 09:38:32 deraadt Exp $ */
+/* $OpenBSD: ip_output.c,v 1.230 2012/07/16 18:05:36 markus Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -120,6 +120,7 @@ ip_output(struct mbuf *m0, ...)
struct inpcb *inp;
struct tdb *tdb;
+ u_int32_t ipsecflowinfo;
int s;
#if NPF > 0
struct ifnet *encif;
@@ -135,6 +136,7 @@ ip_output(struct mbuf *m0, ...)
inp = va_arg(ap, struct inpcb *);
if (inp && (inp->inp_flags & INP_IPV6) != 0)
panic("ip_output: IPv6 pcb is passed");
+ ipsecflowinfo = (flags & IP_IPSECFLOW) ? va_arg(ap, u_int32_t) : 0;
#endif /* IPSEC */
va_end(ap);
@@ -289,7 +291,7 @@ reroute:
}
else
tdb = ipsp_spd_lookup(m, AF_INET, hlen, &error,
- IPSP_DIRECTION_OUT, NULL, inp);
+ IPSP_DIRECTION_OUT, NULL, inp, ipsecflowinfo);
if (tdb == NULL) {
splx(s);
@@ -1061,6 +1063,7 @@ ip_ctloutput(op, so, level, optname, mp)
case IP_RECVTTL:
case IP_RECVDSTPORT:
case IP_RECVRTABLE:
+ case IP_IPSECFLOWINFO:
if (m == NULL || m->m_len != sizeof(int))
error = EINVAL;
else {
@@ -1113,6 +1116,9 @@ ip_ctloutput(op, so, level, optname, mp)
case IP_RECVRTABLE:
OPTSET(INP_RECVRTABLE);
break;
+ case IP_IPSECFLOWINFO:
+ OPTSET(INP_IPSECFLOWINFO);
+ break;
}
}
break;
@@ -1446,6 +1452,7 @@ ip_ctloutput(op, so, level, optname, mp)
case IP_RECVTTL:
case IP_RECVDSTPORT:
case IP_RECVRTABLE:
+ case IP_IPSECFLOWINFO:
*mp = m = m_get(M_WAIT, MT_SOOPTS);
m->m_len = sizeof(int);
switch (optname) {
@@ -1487,6 +1494,9 @@ ip_ctloutput(op, so, level, optname, mp)
case IP_RECVRTABLE:
optval = OPTBIT(INP_RECVRTABLE);
break;
+ case IP_IPSECFLOWINFO:
+ optval = OPTBIT(INP_IPSECFLOWINFO);
+ break;
}
*mtod(m, int *) = optval;
break;
diff --git a/sys/netinet/ip_spd.c b/sys/netinet/ip_spd.c
index 86e12a0d5bc..fecc8af3a75 100644
--- a/sys/netinet/ip_spd.c
+++ b/sys/netinet/ip_spd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_spd.c,v 1.63 2010/09/28 01:44:57 deraadt Exp $ */
+/* $OpenBSD: ip_spd.c,v 1.64 2012/07/16 18:05:36 markus Exp $ */
/*
* The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
*
@@ -79,12 +79,14 @@ int ipsec_acquire_pool_initialized = 0;
*/
struct tdb *
ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int *error, int direction,
- struct tdb *tdbp, struct inpcb *inp)
+ struct tdb *tdbp, struct inpcb *inp, u_int32_t ipsecflowinfo)
{
struct route_enc re0, *re = &re0;
union sockaddr_union sdst, ssrc;
struct sockaddr_encap *ddst;
struct ipsec_policy *ipo;
+ struct ipsec_ref *dstid = NULL, *srcid = NULL;
+ struct tdb *tdbin = NULL;
int signore = 0, dignore = 0;
u_int rdomain = rtable_l2(m->m_pkthdr.rdomain);
@@ -334,6 +336,17 @@ ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int *error, int direction,
/* Outgoing packet policy check. */
if (direction == IPSP_DIRECTION_OUT) {
/*
+ * Fetch the incoming TDB based on the SPI passed
+ * in ipsecflow and use it's dstid when looking
+ * up the outgoing TDB.
+ */
+ if (ipsecflowinfo &&
+ (tdbin = gettdb(rdomain, ipsecflowinfo, &ssrc,
+ ipo->ipo_sproto)) != NULL) {
+ srcid = tdbin->tdb_dstid;
+ dstid = tdbin->tdb_srcid;
+ }
+ /*
* If the packet is destined for the policy-specified
* gateway/endhost, and the socket has the BYPASS
* option set, skip IPsec processing.
@@ -361,7 +374,8 @@ ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int *error, int direction,
goto nomatchout;
if (!ipsp_aux_match(ipo->ipo_tdb,
- ipo->ipo_srcid, ipo->ipo_dstid,
+ srcid ? srcid : ipo->ipo_srcid,
+ dstid ? dstid : ipo->ipo_dstid,
ipo->ipo_local_cred, NULL,
&ipo->ipo_addr, &ipo->ipo_mask))
goto nomatchout;
@@ -397,8 +411,10 @@ ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int *error, int direction,
ipo->ipo_tdb =
gettdbbyaddr(rdomain,
dignore ? &sdst : &ipo->ipo_dst,
- ipo->ipo_sproto, ipo->ipo_srcid,
- ipo->ipo_dstid, ipo->ipo_local_cred, m, af,
+ ipo->ipo_sproto,
+ srcid ? srcid : ipo->ipo_srcid,
+ dstid ? dstid : ipo->ipo_dstid,
+ ipo->ipo_local_cred, m, af,
&ipo->ipo_addr, &ipo->ipo_mask);
if (ipo->ipo_tdb) {
TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head,
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 9fe0fdf817c..fe60ebd6af8 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_var.h,v 1.43 2012/03/17 10:16:41 dlg Exp $ */
+/* $OpenBSD: ip_var.h,v 1.44 2012/07/16 18:05:36 markus Exp $ */
/* $NetBSD: ip_var.h,v 1.16 1996/02/13 23:43:20 christos Exp $ */
/*
@@ -143,6 +143,7 @@ struct ipstat {
#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */
#define IP_MTUDISC 0x0800 /* pmtu discovery, set DF */
#define IP_ROUTETOETHER 0x1000 /* ether addresses given */
+#define IP_IPSECFLOW 0x2000 /* IPsec flow info */
extern struct ipstat ipstat;
extern LIST_HEAD(ipqhead, ipq) ipq; /* ip reass. queue */
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index fd0ac5c9c86..39651b9231c 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.252 2012/03/10 12:03:29 claudio Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.253 2012/07/16 18:05:36 markus Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -912,7 +912,7 @@ findpcb:
} else
tdb = NULL;
ipsp_spd_lookup(m, af, iphlen, &error, IPSP_DIRECTION_IN,
- tdb, inp);
+ tdb, inp, 0);
if (error) {
splx(s);
goto drop;
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 67f5897f775..8e7c92db484 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_usrreq.c,v 1.147 2012/04/04 04:31:38 yasuoka Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.148 2012/07/16 18:05:36 markus Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
@@ -197,6 +197,7 @@ udp_input(struct mbuf *m, ...)
struct m_tag *mtag;
struct tdb_ident *tdbi;
struct tdb *tdb;
+ struct mbuf *iopts = NULL;
int error, s;
#endif /* IPSEC */
@@ -629,7 +630,7 @@ udp_input(struct mbuf *m, ...)
} else
tdb = NULL;
ipsp_spd_lookup(m, srcsa.sa.sa_family, iphlen, &error,
- IPSP_DIRECTION_IN, tdb, inp);
+ IPSP_DIRECTION_IN, tdb, inp, 0);
if (error) {
splx(s);
goto bad;
@@ -671,6 +672,10 @@ udp_input(struct mbuf *m, ...)
inp->inp_tdb_in = NULL;
}
}
+ /* create ipsec options while we know that tdb cannot be modified */
+ if (tdb && (inp->inp_flags & INP_IPSECFLOWINFO))
+ iopts = sbcreatecontrol((caddr_t)&tdb->tdb_spi,
+ sizeof(tdb->tdb_spi), IP_IPSECFLOWINFO, IPPROTO_IP);
splx(s);
#endif /*IPSEC */
@@ -691,6 +696,12 @@ udp_input(struct mbuf *m, ...)
*mp = sbcreatecontrol((caddr_t)&uh->uh_dport, sizeof(u_int16_t),
IP_RECVDSTPORT, IPPROTO_IP);
}
+#ifdef IPSEC
+ if (iopts) {
+ iopts->m_next = opts;
+ opts = iopts; /* prepend */
+ }
+#endif
#ifdef PIPEX
if (pipex_enable && inp->inp_pipex) {
struct pipex_session *session;
@@ -943,6 +954,7 @@ udp_output(struct mbuf *m, ...)
struct inpcb *inp;
struct mbuf *addr, *control;
struct udpiphdr *ui;
+ u_int32_t ipsecflowinfo = 0;
int len = m->m_pkthdr.len;
struct in_addr laddr;
int s = 0, error = 0;
@@ -989,6 +1001,46 @@ udp_output(struct mbuf *m, ...)
goto release;
}
}
+
+#ifdef IPSEC
+ if (control && (inp->inp_flags & INP_IPSECFLOWINFO) != 0) {
+ u_int clen;
+ struct cmsghdr *cm;
+ caddr_t cmsgs;
+
+ /*
+ * XXX: Currently, we assume all the optional information is stored
+ * in a single mbuf.
+ */
+ if (control->m_next) {
+ error = EINVAL;
+ goto bail;
+ }
+
+ clen = control->m_len;
+ cmsgs = mtod(control, caddr_t);
+ do {
+ if (clen < CMSG_LEN(0)) {
+ error = EINVAL;
+ goto bail;
+ }
+ cm = (struct cmsghdr *)cmsgs;
+ if (cm->cmsg_len < CMSG_LEN(0) ||
+ CMSG_ALIGN(cm->cmsg_len) > clen) {
+ error = EINVAL;
+ goto bail;
+ }
+ if (cm->cmsg_len == CMSG_LEN(sizeof(ipsecflowinfo)) &&
+ cm->cmsg_level == IPPROTO_IP &&
+ cm->cmsg_type == IP_IPSECFLOWINFO) {
+ ipsecflowinfo = *(u_int32_t *)CMSG_DATA(cm);
+ break;
+ }
+ clen -= CMSG_ALIGN(cm->cmsg_len);
+ cmsgs += CMSG_ALIGN(cm->cmsg_len);
+ } while (clen);
+ }
+#endif
/*
* Calculate data length and get a mbuf
* for UDP and IP headers.
@@ -1034,8 +1086,8 @@ udp_output(struct mbuf *m, ...)
m->m_pkthdr.rdomain = inp->inp_rtableid;
error = ip_output(m, inp->inp_options, &inp->inp_route,
- inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
- inp->inp_moptions, inp);
+ (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST))
+ |IP_IPSECFLOW, inp->inp_moptions, inp, ipsecflowinfo);
if (error == EACCES) /* translate pf(4) error for userland */
error = EHOSTUNREACH;
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 4045cc1d6a1..3c63ac1c6df 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_forward.c,v 1.53 2011/07/04 06:54:49 claudio Exp $ */
+/* $OpenBSD: ip6_forward.c,v 1.54 2012/07/16 18:05:36 markus Exp $ */
/* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */
/*
@@ -171,7 +171,7 @@ reroute:
m_tag_delete(m, mtag);
} else
tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
- &error, IPSP_DIRECTION_OUT, NULL, NULL);
+ &error, IPSP_DIRECTION_OUT, NULL, NULL, 0);
if (tdb == NULL) {
splx(s);
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 328d561dbeb..07aedeed4d2 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_output.c,v 1.124 2012/04/13 09:38:32 deraadt Exp $ */
+/* $OpenBSD: ip6_output.c,v 1.125 2012/07/16 18:05:36 markus Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@@ -248,7 +248,7 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro,
m_tag_delete(m, mtag);
} else
tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
- &error, IPSP_DIRECTION_OUT, NULL, inp);
+ &error, IPSP_DIRECTION_OUT, NULL, inp, 0);
if (tdb == NULL) {
splx(s);