From owner-svn-src-all@FreeBSD.ORG Wed Jun 23 15:19:08 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 342311065677; Wed, 23 Jun 2010 15:19:08 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 232448FC14; Wed, 23 Jun 2010 15:19:08 +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 o5NFJ8Ks003168; Wed, 23 Jun 2010 15:19:08 GMT (envelope-from tuexen@svn.freebsd.org) Received: (from tuexen@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o5NFJ8rn003166; Wed, 23 Jun 2010 15:19:08 GMT (envelope-from tuexen@svn.freebsd.org) Message-Id: <201006231519.o5NFJ8rn003166@svn.freebsd.org> From: Michael Tuexen Date: Wed, 23 Jun 2010 15:19:07 +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: r209470 - 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: Wed, 23 Jun 2010 15:19:08 -0000 Author: tuexen Date: Wed Jun 23 15:19:07 2010 New Revision: 209470 URL: http://svn.freebsd.org/changeset/base/209470 Log: * Implement sctp_does_stcb_own_this_addr() correclty. It was taking the wrong side into account. * sctp_findassociation_ep_addr() must check the local address if available. This fixes a bug where ABORT chunks were accepted even in the case where the local was not owned by the endpoint. Thanks to brucec for pointing out a bug in my first version of the fix. MFC after: 3 days Modified: head/sys/netinet/sctp_pcb.c Modified: head/sys/netinet/sctp_pcb.c ============================================================================== --- head/sys/netinet/sctp_pcb.c Wed Jun 23 14:28:08 2010 (r209469) +++ head/sys/netinet/sctp_pcb.c Wed Jun 23 15:19:07 2010 (r209470) @@ -1010,6 +1010,149 @@ sctp_tcb_special_locate(struct sctp_inpc return (NULL); } +static int +sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to) +{ + int loopback_scope, ipv4_local_scope, local_scope, site_scope; + int ipv4_addr_legal, ipv6_addr_legal; + struct sctp_vrf *vrf; + struct sctp_ifn *sctp_ifn; + struct sctp_ifa *sctp_ifa; + + loopback_scope = stcb->asoc.loopback_scope; + ipv4_local_scope = stcb->asoc.ipv4_local_scope; + local_scope = stcb->asoc.local_scope; + site_scope = stcb->asoc.site_scope; + ipv4_addr_legal = ipv6_addr_legal = 0; + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { + ipv6_addr_legal = 1; + if (SCTP_IPV6_V6ONLY(stcb->sctp_ep) == 0) { + ipv4_addr_legal = 1; + } + } else { + ipv4_addr_legal = 1; + } + + SCTP_IPI_ADDR_RLOCK(); + vrf = sctp_find_vrf(stcb->asoc.vrf_id); + if (vrf == NULL) { + /* no vrf, no addresses */ + SCTP_IPI_ADDR_RUNLOCK(); + return (0); + } + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { + LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { + if ((loopback_scope == 0) && + SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { + continue; + } + LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { + if (sctp_is_addr_restricted(stcb, sctp_ifa)) + continue; + switch (sctp_ifa->address.sa.sa_family) { +#ifdef INET + case AF_INET: + if (ipv4_addr_legal) { + struct sockaddr_in *sin, + *rsin; + + sin = &sctp_ifa->address.sin; + rsin = (struct sockaddr_in *)to; + if ((ipv4_local_scope == 0) && + IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { + continue; + } + if (sin->sin_addr.s_addr == rsin->sin_addr.s_addr) { + SCTP_IPI_ADDR_RUNLOCK(); + return (1); + } + } + break; +#endif +#ifdef INET6 + case AF_INET6: + if (ipv6_addr_legal) { + struct sockaddr_in6 *sin6, + *rsin6; + + sin6 = &sctp_ifa->address.sin6; + rsin6 = (struct sockaddr_in6 *)to; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + if (local_scope == 0) + continue; + if (sin6->sin6_scope_id == 0) { + if (sa6_recoverscope(sin6) != 0) + continue; + } + } + if ((site_scope == 0) && + (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { + continue; + } + if (SCTP6_ARE_ADDR_EQUAL(sin6, rsin6)) { + SCTP_IPI_ADDR_RUNLOCK(); + return (1); + } + } + break; +#endif + default: + /* TSNH */ + break; + } + } + } + } else { + struct sctp_laddr *laddr; + + LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { + if (sctp_is_addr_restricted(stcb, laddr->ifa)) { + continue; + } + if (laddr->ifa->address.sa.sa_family != to->sa_family) { + continue; + } + switch (to->sa_family) { +#ifdef INET + case AF_INET: + { + struct sockaddr_in *sin, *rsin; + + sin = (struct sockaddr_in *)&laddr->ifa->address.sin; + rsin = (struct sockaddr_in *)to; + if (sin->sin_addr.s_addr == rsin->sin_addr.s_addr) { + SCTP_IPI_ADDR_RUNLOCK(); + return (1); + } + break; + } +#endif +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *sin6, *rsin6; + + sin6 = (struct sockaddr_in6 *)&laddr->ifa->address.sin6; + rsin6 = (struct sockaddr_in6 *)to; + if (SCTP6_ARE_ADDR_EQUAL(sin6, rsin6)) { + SCTP_IPI_ADDR_RUNLOCK(); + return (1); + } + break; + } + +#endif + default: + /* TSNH */ + break; + } + + } + } + SCTP_IPI_ADDR_RUNLOCK(); + return (0); +} + /* * rules for use * @@ -1090,6 +1233,10 @@ sctp_findassociation_ep_addr(struct sctp SCTP_TCB_UNLOCK(stcb); goto null_return; } + if (!(local && sctp_does_stcb_own_this_addr(stcb, local))) { + SCTP_TCB_UNLOCK(stcb); + goto null_return; + } /* now look at the list of remote addresses */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { #ifdef INVARIANTS @@ -1187,6 +1334,10 @@ sctp_findassociation_ep_addr(struct sctp SCTP_TCB_UNLOCK(stcb); continue; } + if (!(local && sctp_does_stcb_own_this_addr(stcb, local))) { + SCTP_TCB_UNLOCK(stcb); + continue; + } /* now look at the list of remote addresses */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { #ifdef INVARIANTS @@ -1800,63 +1951,6 @@ sctp_findassociation_special_addr(struct return (NULL); } -static int -sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to) -{ - struct sctp_nets *net; - - /* - * Simple question, the ports match, does the tcb own the to - * address? - */ - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL)) { - /* of course */ - return (1); - } - /* have to look at all bound addresses */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (net->ro._l_addr.sa.sa_family != to->sa_family) { - /* not the same family, can't be a match */ - continue; - } - switch (to->sa_family) { - case AF_INET: - { - struct sockaddr_in *sin, *rsin; - - sin = (struct sockaddr_in *)&net->ro._l_addr; - rsin = (struct sockaddr_in *)to; - if (sin->sin_addr.s_addr == - rsin->sin_addr.s_addr) { - /* found it */ - return (1); - } - break; - } -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6, *rsin6; - - sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; - rsin6 = (struct sockaddr_in6 *)to; - if (SCTP6_ARE_ADDR_EQUAL(sin6, - rsin6)) { - /* Update the endpoint pointer */ - return (1); - } - break; - } -#endif - default: - /* TSNH */ - break; - } - } - /* Nope, do not have the address ;-( */ - return (0); -} - static struct sctp_tcb * sctp_findassoc_by_vtag(struct sockaddr *from, struct sockaddr *to, uint32_t vtag, struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint16_t rport,