From owner-svn-src-all@FreeBSD.ORG Sat Apr 10 12:05:31 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 88DB71065673; Sat, 10 Apr 2010 12:05:31 +0000 (UTC) (envelope-from bms@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 6CEA08FC1E; Sat, 10 Apr 2010 12:05:31 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o3AC5VCv074268; Sat, 10 Apr 2010 12:05:31 GMT (envelope-from bms@svn.freebsd.org) Received: (from bms@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o3AC5VGp074266; Sat, 10 Apr 2010 12:05:31 GMT (envelope-from bms@svn.freebsd.org) Message-Id: <201004101205.o3AC5VGp074266@svn.freebsd.org> From: Bruce M Simpson Date: Sat, 10 Apr 2010 12:05:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r206452 - head/sys/netinet X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 10 Apr 2010 12:05:31 -0000 Author: bms Date: Sat Apr 10 12:05:31 2010 New Revision: 206452 URL: http://svn.freebsd.org/changeset/base/206452 Log: Fix a few issues related to the legacy 4.4 BSD multicast APIs. IPv4 addresses can and do change during normal operation. Testing by pfSense developers exposed an issue where OpenOSPFD was using the IPv4 address to leave the OSPF link-scope multicast groups on a dynamic OpenVPN tun interface, rather than using RFC 3678 with the interface index, which won't be raced when the interface's addresses change. In inp_join_group(): If we are already a member of an ASM group, and IP_ADD_MEMBERSHIP or MCAST_JOIN_GROUP ioctls are re-issued, return EADDRINUSE as per the legacy 4.4BSD multicast API. This bends RFC 3678 slightly, but does not violate POLA for apps using the old API. It also stops us falling through to kicking IGMP state transactions in what is otherwise a no-op case. [This has already been dealt with in HEAD, but make it explicit before we MFC the change to 8.] In inp_leave_group(): Fix a bogus conditional. Move the ifp null check to ioctls MCAST_LEAVE* in the switch..case where it actually belongs. If an interface was specified, by primary IPv4 address, for ioctl IP_DROP_MEMBERSHIP or MCAST_LEAVE_GROUP (an ASM full leave operation), then and only then should we look up the ifp from the IPv4 address in mreqs.imr_interface. If not, we fall through to imo_match_group() as before, but only in the IP_DROP_MEMBERSHIP case. With these changes, the legacy 4.4BSD multicast API idempotence should be mostly preserved in the SSM enabled IPv4 stack. Found by: ermal (with pfSense) MFC after: 3 days Modified: head/sys/netinet/in_mcast.c Modified: head/sys/netinet/in_mcast.c ============================================================================== --- head/sys/netinet/in_mcast.c Sat Apr 10 11:52:12 2010 (r206451) +++ head/sys/netinet/in_mcast.c Sat Apr 10 12:05:31 2010 (r206452) @@ -1999,9 +1999,12 @@ inp_join_group(struct inpcb *inp, struct } } else { /* - * MCAST_JOIN_GROUP alone, on any existing membership, - * is rejected, to stop the same inpcb tying up - * multiple refs to the in_multi. + * MCAST_JOIN_GROUP on an existing exclusive + * membership is an error; return EADDRINUSE + * to preserve 4.4BSD API idempotence, and + * avoid tedious detour to code below. + * NOTE: This is bending RFC 3678 a bit. + * * On an existing inclusive membership, this is also * an error; if you want to change filter mode, * you must use the userland API setsourcefilter(). @@ -2010,6 +2013,8 @@ inp_join_group(struct inpcb *inp, struct * is atomic with allocation of a membership. */ error = EINVAL; + if (imf->imf_st[1] == MCAST_EXCLUDE) + error = EADDRINUSE; goto out_inp_locked; } } @@ -2186,7 +2191,14 @@ inp_leave_group(struct inpcb *inp, struc ssa->sin.sin_addr = mreqs.imr_sourceaddr; } - if (!in_nullhost(gsa->sin.sin_addr)) + /* + * Attempt to look up hinted ifp from interface address. + * Fallthrough with null ifp iff lookup fails, to + * preserve 4.4BSD mcast API idempotence. + * XXX NOTE WELL: The RFC 3678 API is preferred because + * using an IPv4 address as a key is racy. + */ + if (!in_nullhost(mreqs.imr_interface)) INADDR_TO_IFP(mreqs.imr_interface, ifp); CTR3(KTR_IGMPV3, "%s: imr_interface = %s, ifp = %p", @@ -2222,6 +2234,9 @@ inp_leave_group(struct inpcb *inp, struc return (EADDRNOTAVAIL); ifp = ifnet_byindex(gsr.gsr_interface); + + if (ifp == NULL) + return (EADDRNOTAVAIL); break; default: @@ -2234,9 +2249,6 @@ inp_leave_group(struct inpcb *inp, struc if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) return (EINVAL); - if (ifp == NULL) - return (EADDRNOTAVAIL); - /* * Find the membership in the membership array. */