diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2017-09-06 00:05:03 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2017-09-06 00:05:03 +0000 |
commit | 49deaef3904a2a081b1567814ea2271857aa66ae (patch) | |
tree | 8a5214a8b5499d50e6ae6ab0fc7a485d7c40f4b6 /sys/netinet/ip_divert.c | |
parent | 301c85d3f85bfe5b24412bf721697dc0a01191fe (diff) |
Replace the call to ifa_ifwithaddr() in divert_output() with a route
lookup to make it MP safe. Only set the mbuf header fields that
are needed. Validate the name input.
OK mpi@
Diffstat (limited to 'sys/netinet/ip_divert.c')
-rw-r--r-- | sys/netinet/ip_divert.c | 38 |
1 files changed, 21 insertions, 17 deletions
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index 4233b01c936..9f8821d3559 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_divert.c,v 1.50 2017/09/05 07:59:11 mpi Exp $ */ +/* $OpenBSD: ip_divert.c,v 1.51 2017/09/06 00:05:02 bluhm Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -61,8 +61,6 @@ int *divertctl_vars[DIVERTCTL_MAXID] = DIVERTCTL_VARS; int divbhashsize = DIVERTHASHSIZE; -static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; - int divert_output(struct inpcb *, struct mbuf *, struct mbuf *, struct mbuf *); void @@ -78,18 +76,14 @@ divert_output(struct inpcb *inp, struct mbuf *m, struct mbuf *nam, { struct sockaddr_in *sin; struct socket *so; - struct ifaddr *ifa; - int error = 0, min_hdrlen = 0, dir; + int error, min_hdrlen = 0, dir; struct ip *ip; u_int16_t off; - m->m_pkthdr.ph_ifidx = 0; - m->m_nextpkt = NULL; - m->m_pkthdr.ph_rtableid = inp->inp_rtableid; - m_freem(control); - sin = mtod(nam, struct sockaddr_in *); + if ((error = in_nam2sin(nam, &sin))) + goto fail; so = inp->inp_socket; /* Do basic sanity checks. */ @@ -133,14 +127,17 @@ divert_output(struct inpcb *inp, struct mbuf *m, struct mbuf *nam, m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED_PACKET; if (dir == PF_IN) { - ipaddr.sin_addr = sin->sin_addr; - /* XXXSMP ifa_ifwithaddr() is not safe. */ - ifa = ifa_ifwithaddr(sintosa(&ipaddr), m->m_pkthdr.ph_rtableid); - if (ifa == NULL) { + struct rtentry *rt; + struct ifnet *ifp; + + rt = rtalloc(sintosa(sin), 0, inp->inp_rtableid); + if (!rtisvalid(rt) || !ISSET(rt->rt_flags, RTF_LOCAL)) { + rtfree(rt); error = EADDRNOTAVAIL; goto fail; } - m->m_pkthdr.ph_ifidx = ifa->ifa_ifp->if_index; + m->m_pkthdr.ph_ifidx = rt->rt_ifidx; + rtfree(rt); /* * Recalculate IP and protocol checksums for the inbound packet @@ -151,9 +148,16 @@ divert_output(struct inpcb *inp, struct mbuf *m, struct mbuf *nam, ip->ip_sum = in_cksum(m, off); in_proto_cksum_out(m, NULL); - /* XXXSMP ``ifa'' is not reference counted. */ - ipv4_input(ifa->ifa_ifp, m); + ifp = if_get(m->m_pkthdr.ph_ifidx); + if (ifp == NULL) { + error = ENETDOWN; + goto fail; + } + ipv4_input(ifp, m); + if_put(ifp); } else { + m->m_pkthdr.ph_rtableid = inp->inp_rtableid; + error = ip_output(m, NULL, &inp->inp_route, IP_ALLOWBROADCAST | IP_RAWOUTPUT, NULL, NULL, 0); if (error == EACCES) /* translate pf(4) error for userland */ |