Only use ifa_ifwithaddr() to check if the binding address is on the
authormpi <mpi@openbsd.org>
Wed, 4 Jun 2014 13:45:47 +0000 (13:45 +0000)
committermpi <mpi@openbsd.org>
Wed, 4 Jun 2014 13:45:47 +0000 (13:45 +0000)
system.

Yes, this is ugly for the moment because OpenBSD prevents you from
binding a tcp socket to broadcast address and checking for a broadcast
address is... funny!  If you've ever wondered why would lead people to
write:

ina.s_addr != ia->ia_addr.sin_addr.s_addr

instead of:

ina.s_addr == ia->ia_broadaddr.sin_addr.s_addr

Well this is because all the IPv4 addresses belonging to your lo(4)
interfaces match the second idiom.  Hopefully we'll get rid of this
hack soon.

ok jca@, mikeb@

sys/netinet/in_pcb.c

index ec4d707..6bc1601 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: in_pcb.c,v 1.155 2014/05/07 08:26:38 mpi Exp $        */
+/*     $OpenBSD: in_pcb.c,v 1.156 2014/06/04 13:45:47 mpi Exp $        */
 /*     $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $     */
 
 /*
@@ -261,14 +261,22 @@ in_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p)
                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
                } else if (sin->sin_addr.s_addr != INADDR_ANY) {
                        sin->sin_port = 0;              /* yech... */
-                       if (!(so->so_options & SO_BINDANY) &&
-                           in_iawithaddr(sin->sin_addr,
-                           inp->inp_rtableid) == NULL)
+                       if (!((so->so_options & SO_BINDANY) ||
+                           (sin->sin_addr.s_addr == INADDR_BROADCAST &&
+                            so->so_type == SOCK_DGRAM))) {
+                               struct in_ifaddr *ia;
+
+                               ia = ifatoia(ifa_ifwithaddr(sintosa(sin),
+                                   inp->inp_rtableid));
+                               if (ia == NULL)
+                                       return (EADDRNOTAVAIL);
+
                                /* SOCK_RAW does not use in_pcbbind() */
-                               if (!(so->so_type == SOCK_DGRAM &&
-                                   in_broadcast(sin->sin_addr, NULL,
-                                   inp->inp_rtableid)))
+                               if (so->so_type != SOCK_DGRAM &&
+                                   sin->sin_addr.s_addr !=
+                                   ia->ia_addr.sin_addr.s_addr)
                                        return (EADDRNOTAVAIL);
+                       }
                }
                if (lport) {
                        struct inpcb *t;