When fed a broadcast address, ifa_ifwitaddr() returns the unicast ifa whose broadcast address match the input. This is used mainly to select ifa, and there can be trouble when you have 2 ifas on the same range (e.g. 10.0.0.1/24@em0 & 10.0.0.20/24@em1) :
netinet/ip_mroute.c:814 net/route.c:785 netinet/ip_divert.c:143 net/if_vxlan.c:241 There are also places where broadcast addresses should not be tolerated : netinet/ip_input.c:1061 broadcast address is not a module identifier netinet/ip_input.c:1141 see above netinet/ip_input.c:1197 see above netinet6/*: no broadcast in ipv6 net/route.c:562: gateway shall never be a broadcast addr net/route.c:713: see above This diff removes broadcast matching from ifa_ifwithaddr, and adds or rewrites checks where necessary. Comments ? Ok ? Index: sys/net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.416 diff -u -p -r1.416 if.c --- sys/net/if.c 2 Dec 2015 08:47:00 -0000 1.416 +++ sys/net/if.c 2 Dec 2015 15:17:26 -0000 @@ -1178,13 +1178,6 @@ ifa_ifwithaddr(struct sockaddr *addr, u_ if (equal(addr, ifa->ifa_addr)) return (ifa); - - /* IPv6 doesn't have broadcast */ - if ((ifp->if_flags & IFF_BROADCAST) && - ifa->ifa_broadaddr && - ifa->ifa_broadaddr->sa_len != 0 && - equal(ifa->ifa_broadaddr, addr)) - return (ifa); } } return (NULL); Index: sys/netinet/in_pcb.c =================================================================== RCS file: /cvs/src/sys/netinet/in_pcb.c,v retrieving revision 1.188 diff -u -p -r1.188 in_pcb.c --- sys/netinet/in_pcb.c 30 Oct 2015 09:39:42 -0000 1.188 +++ sys/netinet/in_pcb.c 2 Dec 2015 15:17:26 -0000 @@ -328,14 +328,12 @@ in_pcbbind(struct inpcb *inp, struct mbu 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 && - sin->sin_addr.s_addr != - ia->ia_addr.sin_addr.s_addr) - return (EADDRNOTAVAIL); + if (ia == NULL && + (so->so_type != SOCK_DGRAM || + !in_broadcast(sin->sin_addr, inp->inp_rtableid))) + return (EADDRNOTAVAIL); } } if (lport) { Index: sys/netinet/ip_output.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_output.c,v retrieving revision 1.310 diff -u -p -r1.310 ip_output.c --- sys/netinet/ip_output.c 2 Dec 2015 13:29:26 -0000 1.310 +++ sys/netinet/ip_output.c 2 Dec 2015 15:17:27 -0000 @@ -1387,9 +1387,8 @@ ip_setmoptions(int optname, struct ip_mo sin.sin_family = AF_INET; sin.sin_addr = addr; ia = ifatoia(ifa_ifwithaddr(sintosa(&sin), rtableid)); - if (ia && in_hosteq(sin.sin_addr, ia->ia_addr.sin_addr)) - ifp = ia->ia_ifp; - if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { + if (ia == NULL || (ifp = ia->ia_ifp) == NULL || + (ia->ia_ifp->if_flags & IFF_MULTICAST) == 0) { error = EADDRNOTAVAIL; break; } @@ -1561,12 +1560,11 @@ ip_setmoptions(int optname, struct ip_mo sin.sin_family = AF_INET; sin.sin_addr = mreq->imr_interface; ia = ifatoia(ifa_ifwithaddr(sintosa(&sin), rtableid)); - if (ia && in_hosteq(sin.sin_addr, ia->ia_addr.sin_addr)) - ifp = ia->ia_ifp; - else { + if (ia == NULL) { error = EADDRNOTAVAIL; break; } + ifp = ia->ia_ifp; } /* * Find the membership in the membership array. Index: sys/netinet/raw_ip.c =================================================================== RCS file: /cvs/src/sys/netinet/raw_ip.c,v retrieving revision 1.84 diff -u -p -r1.84 raw_ip.c --- sys/netinet/raw_ip.c 28 Jul 2015 12:22:07 -0000 1.84 +++ sys/netinet/raw_ip.c 2 Dec 2015 15:17:27 -0000 @@ -473,6 +473,7 @@ rip_usrreq(struct socket *so, int req, s if (!((so->so_options & SO_BINDANY) || addr->sin_addr.s_addr == INADDR_ANY || addr->sin_addr.s_addr == INADDR_BROADCAST || + in_broadcast(addr->sin_addr, inp->inp_rtableid) || ifa_ifwithaddr(sintosa(addr), inp->inp_rtableid))) { error = EADDRNOTAVAIL; break;