On Tue, Sep 05, 2017 at 12:48:59AM +0200, Alexander Bluhm wrote:
> This replaces 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.

And here is the same diff for IPv6, remove ifa_ifwithaddr() from
divert6_output().

Also use the same variables in both functions and avoid unneccessary
initialization.

ok?

bluhm

Index: netinet/ip_divert.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_divert.c,v
retrieving revision 1.51
diff -u -p -r1.51 ip_divert.c
--- netinet/ip_divert.c 6 Sep 2017 00:05:02 -0000       1.51
+++ netinet/ip_divert.c 6 Sep 2017 00:32:37 -0000
@@ -75,16 +75,13 @@ divert_output(struct inpcb *inp, struct 
     struct mbuf *control)
 {
        struct sockaddr_in *sin;
-       struct socket *so;
-       int error, min_hdrlen = 0, dir;
+       int error, min_hdrlen, off, dir;
        struct ip *ip;
-       u_int16_t off;
 
        m_freem(control);
 
        if ((error = in_nam2sin(nam, &sin)))
                goto fail;
-       so = inp->inp_socket;
 
        /* Do basic sanity checks. */
        if (m->m_pkthdr.len < sizeof(struct ip))
@@ -118,7 +115,7 @@ divert_output(struct inpcb *inp, struct 
                m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
                break;
        default:
-               /* nothing */
+               min_hdrlen = 0;
                break;
        }
        if (min_hdrlen && m->m_pkthdr.len < off + min_hdrlen)
Index: netinet6/ip6_divert.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_divert.c,v
retrieving revision 1.50
diff -u -p -r1.50 ip6_divert.c
--- netinet6/ip6_divert.c       5 Sep 2017 07:59:11 -0000       1.50
+++ netinet6/ip6_divert.c       6 Sep 2017 00:38:53 -0000
@@ -62,8 +62,6 @@ int *divert6ctl_vars[DIVERT6CTL_MAXID] =
 
 int divb6hashsize = DIVERTHASHSIZE;
 
-static struct sockaddr_in6 ip6addr = { sizeof(ip6addr), AF_INET6 };
-
 int    divert6_output(struct inpcb *, struct mbuf *, struct mbuf *,
            struct mbuf *);
 
@@ -79,17 +77,13 @@ divert6_output(struct inpcb *inp, struct
     struct mbuf *control)
 {
        struct sockaddr_in6 *sin6;
-       struct ifaddr *ifa;
-       int error = 0, min_hdrlen = 0, nxt = 0, off, dir;
+       int error, min_hdrlen, nxt, off, dir;
        struct ip6_hdr *ip6;
 
-       m->m_pkthdr.ph_ifidx = 0;
-       m->m_nextpkt = NULL;
-       m->m_pkthdr.ph_rtableid = inp->inp_rtableid;
-
        m_freem(control);
 
-       sin6 = mtod(nam, struct sockaddr_in6 *);
+       if ((error = in6_nam2sin6(nam, &sin6)))
+               goto fail;
 
        /* Do basic sanity checks. */
        if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
@@ -129,7 +123,7 @@ divert6_output(struct inpcb *inp, struct
                m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
                break;
        default:
-               /* nothing */
+               min_hdrlen = 0;
                break;
        }
        if (min_hdrlen && m->m_pkthdr.len < off + min_hdrlen)
@@ -138,15 +132,17 @@ divert6_output(struct inpcb *inp, struct
        m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED_PACKET;
 
        if (dir == PF_IN) {
-               ip6addr.sin6_addr = sin6->sin6_addr;
-               /* XXXSMP ``ifa'' is not reference counted. */
-               ifa = ifa_ifwithaddr(sin6tosa(&ip6addr),
-                   m->m_pkthdr.ph_rtableid);
-               if (ifa == NULL) {
+               struct rtentry *rt;
+               struct ifnet *ifp;
+
+               rt = rtalloc(sin6tosa(sin6), 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 the protocol checksum for the inbound packet
@@ -155,9 +151,16 @@ divert6_output(struct inpcb *inp, struct
                 */
                in6_proto_cksum_out(m, NULL);
 
-               /* XXXSMP ``ifa'' is not reference counted. */
-               ipv6_input(ifa->ifa_ifp, m);
+               ifp = if_get(m->m_pkthdr.ph_ifidx);
+               if (ifp == NULL) {
+                       error = ENETDOWN;
+                       goto fail;
+               }
+               ipv6_input(ifp, m);
+               if_put(ifp);
        } else {
+               m->m_pkthdr.ph_rtableid = inp->inp_rtableid;
+
                error = ip6_output(m, NULL, &inp->inp_route6,
                    IP_ALLOWBROADCAST | IP_RAWOUTPUT, NULL, NULL);
        }

Reply via email to