summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2015-12-02 20:50:21 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2015-12-02 20:50:21 +0000
commitfc16e188f4983ac32fc115da6fd3bea4d9ced56f (patch)
treefc761e4ca750af299afd6e3a61c02957ff7933ae /sys
parent30df0e4c734820d5f1f7a88171e7c96983000fc0 (diff)
factor out ip_output_ipsec_{lookup,send}(); with & ok claudio@
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/ip_output.c311
1 files changed, 146 insertions, 165 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 0c1c8f8f291..be594fbb66f 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.310 2015/12/02 13:29:26 claudio Exp $ */
+/* $OpenBSD: ip_output.c,v 1.311 2015/12/02 20:50:20 markus Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -78,6 +78,13 @@ static __inline u_int16_t __attribute__((__unused__))
in_cksum_phdr(u_int32_t, u_int32_t, u_int32_t);
void in_delayed_cksum(struct mbuf *);
+struct tdb *
+ip_output_ipsec_lookup(struct mbuf *m, int hlen, int *error, struct inpcb *inp,
+ int ipsecflowinfo);
+int
+ip_output_ipsec_send(struct tdb *tdb, struct mbuf *m, struct ifnet *ifp,
+ struct route *ro);
+
/*
* IP output. The packet in mbuf chain m contains a skeletal IP
* header (with len, off, ttl, proto, tos, src, dst).
@@ -96,20 +103,8 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
struct route iproute;
struct sockaddr_in *dst;
struct in_ifaddr *ia;
- u_int8_t sproto = 0;
+ struct tdb *tdb = NULL;
u_long mtu;
-#ifdef IPSEC
- u_int32_t icmp_mtu = 0;
- union sockaddr_union sdst;
- u_int32_t sspi;
- struct m_tag *mtag;
- struct tdb_ident *tdbi;
-
- struct tdb *tdb;
-#if NPF > 0
- struct ifnet *encif;
-#endif
-#endif /* IPSEC */
#ifdef IPSEC
if (inp && (inp->inp_flags & INP_IPV6) != 0)
@@ -217,70 +212,30 @@ reroute:
ip->ip_src = ia->ia_addr.sin_addr;
#ifdef IPSEC
- if (!ipsec_in_use && inp == NULL)
- goto done_spd;
-
- /* Do we have any pending SAs to apply ? */
- tdb = ipsp_spd_lookup(m, AF_INET, hlen, &error,
- IPSP_DIRECTION_OUT, NULL, inp, ipsecflowinfo);
-
- if (tdb == NULL) {
- if (error == 0) {
- /*
- * No IPsec processing required, we'll just send the
- * packet out.
- */
- sproto = 0;
-
- /* Fall through to routing/multicast handling */
- } else {
- /*
- * -EINVAL is used to indicate that the packet should
- * be silently dropped, typically because we've asked
- * key management for an SA.
- */
- if (error == -EINVAL) /* Should silently drop packet */
- error = 0;
-
+ if (ipsec_in_use || inp != NULL) {
+ /* Do we have any pending SAs to apply ? */
+ tdb = ip_output_ipsec_lookup(m, hlen, &error, inp,
+ ipsecflowinfo);
+ if (error != 0) {
+ /* Should silently drop packet */
+ if (error == -EINVAL)
+ error = 0;
m_freem(m);
goto done;
}
- } else {
- /* Loop detection */
- for (mtag = m_tag_first(m); mtag != NULL;
- mtag = m_tag_next(m, mtag)) {
- if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE)
- continue;
- tdbi = (struct tdb_ident *)(mtag + 1);
- if (tdbi->spi == tdb->tdb_spi &&
- tdbi->proto == tdb->tdb_sproto &&
- tdbi->rdomain == tdb->tdb_rdomain &&
- !memcmp(&tdbi->dst, &tdb->tdb_dst,
- sizeof(union sockaddr_union))) {
- sproto = 0; /* mark as no-IPsec-needed */
- goto done_spd;
- }
- }
-
- /* We need to do IPsec */
- bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
- sspi = tdb->tdb_spi;
- sproto = tdb->tdb_sproto;
-
- /*
- * If it needs TCP/UDP hardware-checksumming, do the
- * computation now.
- */
- in_proto_cksum_out(m, NULL);
+ if (tdb != NULL) {
+ /*
+ * If it needs TCP/UDP hardware-checksumming, do the
+ * computation now.
+ */
+ in_proto_cksum_out(m, NULL);
- /* If it's not a multicast packet, try to fast-path */
- if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
- goto sendit;
+ /* If it's not a multicast packet, try to fast-path */
+ if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
+ goto sendit;
+ }
}
}
-
- /* Fall through to the routing/multicast handling code */
- done_spd:
#endif /* IPSEC */
if (IN_MULTICAST(ip->ip_dst.s_addr) ||
@@ -323,7 +278,7 @@ reroute:
if ((((m->m_flags & M_MCAST) &&
(ifp->if_flags & IFF_MULTICAST) == 0) ||
((m->m_flags & M_BCAST) &&
- (ifp->if_flags & IFF_BROADCAST) == 0)) && (sproto == 0)) {
+ (ifp->if_flags & IFF_BROADCAST) == 0)) && (tdb == NULL)) {
ipstat.ips_noroute++;
error = ENETUNREACH;
goto bad;
@@ -401,7 +356,7 @@ reroute:
* such a packet; if the packet is going in an IPsec tunnel, skip
* this check.
*/
- if ((sproto == 0) && ((dst->sin_addr.s_addr == INADDR_BROADCAST) ||
+ if ((tdb == NULL) && ((dst->sin_addr.s_addr == INADDR_BROADCAST) ||
(ro && ro->ro_rt && ISSET(ro->ro_rt->rt_flags, RTF_BROADCAST)))) {
if ((ifp->if_flags & IFF_BROADCAST) == 0) {
error = EADDRNOTAVAIL;
@@ -434,93 +389,10 @@ sendit:
/*
* Check if the packet needs encapsulation.
*/
- if (sproto != 0) {
- tdb = gettdb(rtable_l2(m->m_pkthdr.ph_rtableid),
- sspi, &sdst, sproto);
- if (tdb == NULL) {
- DPRINTF(("ip_output: unknown TDB"));
- error = EHOSTUNREACH;
- m_freem(m);
- goto done;
- }
-
- /*
- * Packet filter
- */
-#if NPF > 0
- if ((encif = enc_getif(tdb->tdb_rdomain,
- tdb->tdb_tap)) == NULL ||
- pf_test(AF_INET, PF_OUT, encif, &m) != PF_PASS) {
- error = EACCES;
- m_freem(m);
- goto done;
- }
- if (m == NULL) {
- goto done;
- }
- ip = mtod(m, struct ip *);
- hlen = ip->ip_hl << 2;
- /*
- * PF_TAG_REROUTE handling or not...
- * Packet is entering IPsec so the routing is
- * already overruled by the IPsec policy.
- * Until now the change was not reconsidered.
- * What's the behaviour?
- */
- in_proto_cksum_out(m, encif);
-#endif
-
- /* Check if we are allowed to fragment */
- if (ip_mtudisc && (ip->ip_off & htons(IP_DF)) && tdb->tdb_mtu &&
- ntohs(ip->ip_len) > tdb->tdb_mtu &&
- tdb->tdb_mtutimeout > time_second) {
- struct rtentry *rt = NULL;
- int rt_mtucloned = 0;
- int transportmode = 0;
-
- transportmode = (tdb->tdb_dst.sa.sa_family == AF_INET) &&
- (tdb->tdb_dst.sin.sin_addr.s_addr ==
- ip->ip_dst.s_addr);
- icmp_mtu = tdb->tdb_mtu;
-
- /* Find a host route to store the mtu in */
- if (ro != NULL)
- rt = ro->ro_rt;
- /* but don't add a PMTU route for transport mode SAs */
- if (transportmode)
- rt = NULL;
- else if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0) {
- rt = icmp_mtudisc_clone(ip->ip_dst,
- m->m_pkthdr.ph_rtableid);
- rt_mtucloned = 1;
- }
- DPRINTF(("ip_output: spi %08x mtu %d rt %p cloned %d\n",
- ntohl(tdb->tdb_spi), icmp_mtu, rt, rt_mtucloned));
- if (rt != NULL) {
- rt->rt_rmx.rmx_mtu = icmp_mtu;
- if (ro && ro->ro_rt != NULL) {
- rtfree(ro->ro_rt);
- ro->ro_rt = rtalloc(&ro->ro_dst,
- RT_RESOLVE,
- m->m_pkthdr.ph_rtableid);
- }
- if (rt_mtucloned)
- rtfree(rt);
- }
- error = EMSGSIZE;
- goto bad;
- }
-
- /*
- * Clear these -- they'll be set in the recursive invocation
- * as needed.
- */
- m->m_flags &= ~(M_MCAST | M_BCAST);
-
+ if (tdb != NULL) {
/* Callee frees mbuf */
- error = ipsp_process_packet(m, tdb, AF_INET, 0);
- if_put(ifp);
- return error; /* Nothing more to be done */
+ error = ip_output_ipsec_send(tdb, m, ifp, ro);
+ goto done;
}
#endif /* IPSEC */
@@ -583,7 +455,8 @@ sendit:
*/
if (ip->ip_off & htons(IP_DF)) {
#ifdef IPSEC
- icmp_mtu = ifp->if_mtu;
+ if (ip_mtudisc)
+ ipsec_adjust_mtu(m, ifp->if_mtu);
#endif
error = EMSGSIZE;
/*
@@ -627,14 +500,122 @@ done:
if_put(ifp);
return (error);
bad:
-#ifdef IPSEC
- if (error == EMSGSIZE && ip_mtudisc && icmp_mtu != 0 && m != NULL)
- ipsec_adjust_mtu(m, icmp_mtu);
-#endif
m_freem(m0);
goto done;
}
+#ifdef IPSEC
+struct tdb *
+ip_output_ipsec_lookup(struct mbuf *m, int hlen, int *error, struct inpcb *inp,
+ int ipsecflowinfo)
+{
+ struct m_tag *mtag;
+ struct tdb_ident *tdbi;
+ struct tdb *tdb;
+
+ /* Do we have any pending SAs to apply ? */
+ tdb = ipsp_spd_lookup(m, AF_INET, hlen, error, IPSP_DIRECTION_OUT,
+ NULL, inp, ipsecflowinfo);
+ if (tdb == NULL)
+ return NULL;
+ /* Loop detection */
+ for (mtag = m_tag_first(m); mtag != NULL; mtag = m_tag_next(m, mtag)) {
+ if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE)
+ continue;
+ tdbi = (struct tdb_ident *)(mtag + 1);
+ if (tdbi->spi == tdb->tdb_spi &&
+ tdbi->proto == tdb->tdb_sproto &&
+ tdbi->rdomain == tdb->tdb_rdomain &&
+ !memcmp(&tdbi->dst, &tdb->tdb_dst,
+ sizeof(union sockaddr_union))) {
+ /* no IPsec needed */
+ return NULL;
+ }
+ }
+ return tdb;
+}
+
+int
+ip_output_ipsec_send(struct tdb *tdb, struct mbuf *m, struct ifnet *ifp,
+ struct route *ro)
+{
+#if NPF > 0
+ struct ifnet *encif;
+#endif
+ struct ip *ip;
+
+#if NPF > 0
+ /*
+ * Packet filter
+ */
+ if ((encif = enc_getif(tdb->tdb_rdomain, tdb->tdb_tap)) == NULL ||
+ pf_test(AF_INET, PF_OUT, encif, &m) != PF_PASS) {
+ m_freem(m);
+ return EACCES;
+ }
+ if (m == NULL)
+ return 0;
+ /*
+ * PF_TAG_REROUTE handling or not...
+ * Packet is entering IPsec so the routing is
+ * already overruled by the IPsec policy.
+ * Until now the change was not reconsidered.
+ * What's the behaviour?
+ */
+ in_proto_cksum_out(m, encif);
+#endif
+
+ /* Check if we are allowed to fragment */
+ ip = mtod(m, struct ip *);
+ if (ip_mtudisc && (ip->ip_off & htons(IP_DF)) && tdb->tdb_mtu &&
+ ntohs(ip->ip_len) > tdb->tdb_mtu &&
+ tdb->tdb_mtutimeout > time_second) {
+ struct rtentry *rt = NULL;
+ int rt_mtucloned = 0;
+ int transportmode = 0;
+
+ transportmode = (tdb->tdb_dst.sa.sa_family == AF_INET) &&
+ (tdb->tdb_dst.sin.sin_addr.s_addr == ip->ip_dst.s_addr);
+
+ /* Find a host route to store the mtu in */
+ if (ro != NULL)
+ rt = ro->ro_rt;
+ /* but don't add a PMTU route for transport mode SAs */
+ if (transportmode)
+ rt = NULL;
+ else if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0) {
+ rt = icmp_mtudisc_clone(ip->ip_dst,
+ m->m_pkthdr.ph_rtableid);
+ rt_mtucloned = 1;
+ }
+ DPRINTF(("%s: spi %08x mtu %d rt %p cloned %d\n", __func__,
+ ntohl(tdb->tdb_spi), tdb->tdb_mtu, rt, rt_mtucloned));
+ if (rt != NULL) {
+ rt->rt_rmx.rmx_mtu = tdb->tdb_mtu;
+ if (ro && ro->ro_rt != NULL) {
+ rtfree(ro->ro_rt);
+ ro->ro_rt = rtalloc(&ro->ro_dst, RT_RESOLVE,
+ m->m_pkthdr.ph_rtableid);
+ }
+ if (rt_mtucloned)
+ rtfree(rt);
+ }
+ ipsec_adjust_mtu(m, tdb->tdb_mtu);
+ m_freem(m);
+ return EMSGSIZE;
+ }
+
+ /*
+ * Clear these -- they'll be set in the recursive invocation
+ * as needed.
+ */
+ m->m_flags &= ~(M_MCAST | M_BCAST);
+
+ /* Callee frees mbuf */
+ return ipsp_process_packet(m, tdb, AF_INET, 0);
+}
+#endif /* IPSEC */
+
int
ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu)
{