Hi,

Checking for IPv4 mapped addresses is a bit inconsistent in the
output path.  So I would like to:

- Use the common switch(af) construct for af specific code in
  tcp_usrreq(PRU_CONNECT).
- Add a EAFNOSUPPORT default case.
- Do not check for mapped addresses, this is done in in6_pcbconnect().

- Do not check for locally bound mapped addresses in
  in6_pcbconnect(), this is done during bind(2) in in6_pcbaddrisavail().

- Check for mapped addesses in rip6_output() like it is done
  in udp6_output().
- Move the EAFNOSUPPORT error from rip6_usrreq() to rip6_output()
  like it is done for UDP.

- Return EADDRNOTAVAIL if UDP sendto(2) is used with a mapped address.

ok?

bluhm

Index: netinet/tcp_usrreq.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.147
diff -u -p -r1.147 tcp_usrreq.c
--- netinet/tcp_usrreq.c        5 Apr 2017 13:35:18 -0000       1.147
+++ netinet/tcp_usrreq.c        8 May 2017 13:23:50 -0000
@@ -127,7 +127,6 @@ int
 tcp_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
     struct mbuf *control, struct proc *p)
 {
-       struct sockaddr_in *sin;
        struct inpcb *inp;
        struct tcpcb *tp = NULL;
        int error = 0;
@@ -221,33 +220,40 @@ tcp_usrreq(struct socket *so, int req, s
         * Send initial segment on connection.
         */
        case PRU_CONNECT:
-               sin = mtod(nam, struct sockaddr_in *);
-
-#ifdef INET6
-               if (sin->sin_family == AF_INET6) {
-                       struct in6_addr *in6_addr = &mtod(nam,
-                           struct sockaddr_in6 *)->sin6_addr;
-
-                       if (IN6_IS_ADDR_UNSPECIFIED(in6_addr) ||
-                           IN6_IS_ADDR_MULTICAST(in6_addr) ||
-                           IN6_IS_ADDR_V4MAPPED(in6_addr)) {
+               switch (mtod(nam, struct sockaddr *)->sa_family) {
+               case AF_INET: {
+                       struct in_addr *addr =
+                           &mtod(nam, struct sockaddr_in *)->sin_addr;
+
+                       if ((addr->s_addr == INADDR_ANY) ||
+                           (addr->s_addr == INADDR_BROADCAST) ||
+                           IN_MULTICAST(addr->s_addr) ||
+                           in_broadcast(*addr, inp->inp_rtableid)) {
                                error = EINVAL;
                                break;
                        }
 
-                       error = in6_pcbconnect(inp, nam);
-               } else if (sin->sin_family == AF_INET)
-#endif /* INET6 */
-               {
-                       if ((sin->sin_addr.s_addr == INADDR_ANY) ||
-                           (sin->sin_addr.s_addr == INADDR_BROADCAST) ||
-                           IN_MULTICAST(sin->sin_addr.s_addr) ||
-                           in_broadcast(sin->sin_addr, inp->inp_rtableid)) {
+                       error = in_pcbconnect(inp, nam);
+                       break;
+               }
+#ifdef INET6
+               case AF_INET6: {
+                       struct in6_addr *addr6 =
+                           &mtod(nam, struct sockaddr_in6 *)->sin6_addr;
+
+                       if (IN6_IS_ADDR_UNSPECIFIED(addr6) ||
+                           IN6_IS_ADDR_MULTICAST(addr6)) {
                                error = EINVAL;
                                break;
                        }
 
-                       error = in_pcbconnect(inp, nam);
+                       error = in6_pcbconnect(inp, nam);
+                       break;
+               }
+#endif /* INET6 */
+               default:
+                       error = EAFNOSUPPORT;
+                       break;
                }
 
                if (error)
Index: netinet6/in6_pcb.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/in6_pcb.c,v
retrieving revision 1.97
diff -u -p -r1.97 in6_pcb.c
--- netinet6/in6_pcb.c  7 Mar 2017 16:59:40 -0000       1.97
+++ netinet6/in6_pcb.c  8 May 2017 13:23:50 -0000
@@ -256,14 +256,9 @@ in6_pcbconnect(struct inpcb *inp, struct
                return (EAFNOSUPPORT);
        if (sin6->sin6_port == 0)
                return (EADDRNOTAVAIL);
-
        /* reject IPv4 mapped address, we have no support for it */
        if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
-               return EADDRNOTAVAIL;
-
-       /* sanity check for mapped address case */
-       if (IN6_IS_ADDR_V4MAPPED(&inp->inp_laddr6))
-               return EINVAL;
+               return (EADDRNOTAVAIL);
 
        /* protect *sin6 from overwrites */
        tmp = *sin6;
Index: netinet6/raw_ip6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/raw_ip6.c,v
retrieving revision 1.113
diff -u -p -r1.113 raw_ip6.c
--- netinet6/raw_ip6.c  8 May 2017 08:46:39 -0000       1.113
+++ netinet6/raw_ip6.c  8 May 2017 14:16:27 -0000
@@ -343,7 +343,6 @@ rip6_output(struct mbuf *m, struct socke
        priv = 0;
        if ((so->so_state & SS_PRIV) != 0)
                priv = 1;
-       dst = &satosin6(dstaddr)->sin6_addr;
        if (control) {
                if ((error = ip6_setpktopts(control, &opt,
                    in6p->inp_outputopts6,
@@ -353,6 +352,16 @@ rip6_output(struct mbuf *m, struct socke
        } else
                optp = in6p->inp_outputopts6;
 
+       if (dstaddr->sa_family != AF_INET6) {
+               error = EAFNOSUPPORT;
+               goto bad;
+       }
+       dst = &satosin6(dstaddr)->sin6_addr;
+       if (IN6_IS_ADDR_V4MAPPED(dst)) {
+               error = EADDRNOTAVAIL;
+               goto bad;
+       }
+
        /*
         * For an ICMPv6 packet, we should know its type and code
         * to update statistics.
@@ -691,11 +700,6 @@ rip6_usrreq(struct socket *so, int req, 
 
                        tmp = *mtod(nam, struct sockaddr_in6 *);
                        dst = &tmp;
-
-                       if (dst->sin6_family != AF_INET6) {
-                               error = EAFNOSUPPORT;
-                               break;
-                       }
                }
                error = rip6_output(m, so, sin6tosa(dst), control);
                m = NULL;
Index: netinet6/udp6_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/udp6_output.c,v
retrieving revision 1.53
diff -u -p -r1.53 udp6_output.c
--- netinet6/udp6_output.c      19 Dec 2016 15:47:19 -0000      1.53
+++ netinet6/udp6_output.c      8 May 2017 13:23:50 -0000
@@ -132,7 +132,7 @@ udp6_output(struct inpcb *in6p, struct m
                        goto release;
                }
                if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
-                       error = EINVAL;
+                       error = EADDRNOTAVAIL;
                        goto release;
                }
 

Reply via email to