in_pcbbind and in6_pcbbind both extends SO_REUSEADDR for multicast
addresses so that it turns into a SO_REUSEPORT. But the check is done
in such a way that you cannot bind a SO_REUSEPORT-enabled socket to a
multicast address *after* you bound a SO_REUSEADDR-enabled socket to
the same address.

*But:* due to how the struct in_pcb are handled, if you :
1) bind a SO_REUSEADDR-enabled socket to a multicast address,
2) then bind a SO_REUSEADDR|SO_REUSEPORT-enabled socket to the same address,
as a result you can now bind a SO_REUSEPORT-enabled socket to this address.

The regress test in regress/sys/netinet/in_pcbbind reproduce this behaviour
(be sure to get v1.2 for Makefile and runtest.c)

This diff allow SO_REUSEPORT-only socket to be bound after SO_REUSEADDR-only.

ok ?

Index: netinet/in_pcb.c
===================================================================
RCS file: /cvs/src/sys/netinet/in_pcb.c,v
retrieving revision 1.194
diff -u -p -r1.194 in_pcb.c
--- netinet/in_pcb.c    3 Dec 2015 21:57:59 -0000       1.194
+++ netinet/in_pcb.c    9 Dec 2015 15:22:16 -0000
@@ -318,7 +318,7 @@ in_pcbbind(struct inpcb *inp, struct mbu
                         * and a multicast address is bound on both
                         * new and duplicated sockets.
                         */
-                       if (so->so_options & SO_REUSEADDR)
+                       if (so->so_options & (SO_REUSEADDR|SO_REUSEPORT))
                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
                } else if (sin->sin_addr.s_addr != INADDR_ANY) {
                        sin->sin_port = 0;              /* yech... */
Index: netinet6/in6_pcb.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_pcb.c,v
retrieving revision 1.83
diff -u -p -r1.83 in6_pcb.c
--- netinet6/in6_pcb.c  2 Dec 2015 22:13:44 -0000       1.83
+++ netinet6/in6_pcb.c  9 Dec 2015 15:22:16 -0000
@@ -214,7 +214,7 @@ in6_pcbbind(struct inpcb *inp, struct mb
                         * and a multicast address is bound on both
                         * new and duplicated sockets.
                         */
-                       if (so->so_options & SO_REUSEADDR)
+                       if (so->so_options & (SO_REUSEADDR|SO_REUSEPORT))
                                reuseport = SO_REUSEADDR | SO_REUSEPORT;
                } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
                        struct ifaddr *ifa = NULL;

Reply via email to