From owner-svn-src-all@FreeBSD.ORG Sat May 14 18:22:16 2011 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 9099D1065768; Sat, 14 May 2011 18:22:15 +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 503CE8FC0C; Sat, 14 May 2011 18:22:15 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p4EIMFNT011326; Sat, 14 May 2011 18:22:15 GMT (envelope-from tuexen@svn.freebsd.org) Received: (from tuexen@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p4EIMFuB011323; Sat, 14 May 2011 18:22:15 GMT (envelope-from tuexen@svn.freebsd.org) Message-Id: <201105141822.p4EIMFuB011323@svn.freebsd.org> From: Michael Tuexen Date: Sat, 14 May 2011 18:22:15 +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: r221904 - 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, 14 May 2011 18:22:16 -0000 Author: tuexen Date: Sat May 14 18:22:14 2011 New Revision: 221904 URL: http://svn.freebsd.org/changeset/base/221904 Log: Fix the source address selection for boundall sockets when sending INITs to a global IPv4 address having only private IPv4 address. Allow the usage of a private address and make sure that no other private address will be used by the association. Initial work was done by rrs@. MFC after: 1 week. Modified: head/sys/netinet/sctp_output.c head/sys/netinet/sctp_output.h Modified: head/sys/netinet/sctp_output.c ============================================================================== --- head/sys/netinet/sctp_output.c Sat May 14 18:22:08 2011 (r221903) +++ head/sys/netinet/sctp_output.c Sat May 14 18:22:14 2011 (r221904) @@ -2022,7 +2022,8 @@ sctp_add_addr_to_mbuf(struct mbuf *m, st struct mbuf * -sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_scoping *scope, +sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_tcb *stcb, + struct sctp_scoping *scope, struct mbuf *m_at, int cnt_inits_to) { struct sctp_vrf *vrf = NULL; @@ -2056,6 +2057,9 @@ sctp_add_addresses_to_i_ia(struct sctp_i continue; } LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) { + if (sctp_is_addr_restricted(stcb, sctp_ifap)) { + continue; + } if (sctp_is_address_in_scope(sctp_ifap, scope->ipv4_addr_legal, scope->ipv6_addr_legal, @@ -2088,6 +2092,9 @@ skip_count: continue; } LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) { + if (sctp_is_addr_restricted(stcb, sctp_ifap)) { + continue; + } if (sctp_is_address_in_scope(sctp_ifap, scope->ipv4_addr_legal, scope->ipv6_addr_legal, @@ -2295,32 +2302,46 @@ sctp_is_ifa_addr_acceptable(struct sctp_ { uint8_t dest_is_global = 0; - /* + /** * Here we determine if its a acceptable address. A acceptable * address means it is the same scope or higher scope but we can * allow for NAT which means its ok to have a global dest and a * private src. - * + * * L = loopback, P = private, G = global - * ----------------------------------------- src | dest | result - * ----------------------------------------- L | L | yes - * ----------------------------------------- P | L | - * yes-v4 no-v6 ----------------------------------------- G | - * L | yes ----------------------------------------- L | - * P | no ----------------------------------------- P | P - * | yes ----------------------------------------- G | P - * | yes - May not work ----------------------------------------- - * L | G | no ----------------------------------------- P - * | G | yes - May not work - * ----------------------------------------- G | G | yes + * ----------------------------------------- + * src | dest | result + * ----------------------------------------- + * L | L | yes + * ----------------------------------------- + * P | L | yes-v4 no-v6 + * ----------------------------------------- + * G | L | yes + * ----------------------------------------- + * L | P | no + * ----------------------------------------- + * P | P | yes + * ----------------------------------------- + * G | P | yes - May not work + * ----------------------------------------- + * L | G | no + * ----------------------------------------- + * P | G | yes - May not work + * ----------------------------------------- + * G | G | yes * ----------------------------------------- */ if (ifa->address.sa.sa_family != fam) { /* forget non matching family */ + SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa_fam:%d fam:%d\n", + ifa->address.sa.sa_family, fam); return (NULL); } /* Ok the address may be ok */ + SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT3, &ifa->address.sa); + SCTPDBG(SCTP_DEBUG_OUTPUT3, "dst_is_loop:%d dest_is_priv:%d\n", + dest_is_loop, dest_is_priv); if ((dest_is_loop == 0) && (dest_is_priv == 0)) { dest_is_global = 1; } @@ -2342,12 +2363,19 @@ sctp_is_ifa_addr_acceptable(struct sctp_ * theory be done slicker (it used to be), but this is * straightforward and easier to validate :-) */ + SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa->src_is_loop:%d dest_is_priv:%d\n", + ifa->src_is_loop, + dest_is_priv); if ((ifa->src_is_loop == 1) && (dest_is_priv)) { return (NULL); } + SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa->src_is_loop:%d dest_is_glob:%d\n", + ifa->src_is_loop, + dest_is_global); if ((ifa->src_is_loop == 1) && (dest_is_global)) { return (NULL); } + SCTPDBG(SCTP_DEBUG_OUTPUT3, "address is acceptable\n"); /* its an acceptable address */ return (ifa); } @@ -2854,6 +2882,10 @@ sctp_choose_boundall(struct sctp_inpcb * uint32_t ifn_index; struct sctp_vrf *vrf; +#ifdef INET + int retried = 0; + +#endif /*- * For boundall we can use any address in the association. * If non_asoc_addr_ok is set we can use any address (at least in @@ -2874,6 +2906,7 @@ sctp_choose_boundall(struct sctp_inpcb * ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro); ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifn from route:%p ifn_index:%d\n", ifn, ifn_index); emit_ifn = looked_at = sctp_ifn = sctp_find_ifn(ifn, ifn_index); if (sctp_ifn == NULL) { /* ?? We don't have this guy ?? */ @@ -2982,22 +3015,30 @@ bound_all_plan_b: } atomic_add_int(&sifa->refcount, 1); return (sifa); - } - +#ifdef INET +again_with_private_addresses_allowed: +#endif /* plan_c: do we have an acceptable address on the emit interface */ + sifa = NULL; SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan C: find acceptable on interface\n"); if (emit_ifn == NULL) { + SCTPDBG(SCTP_DEBUG_OUTPUT2, "Jump to Plan D - no emit_ifn\n"); goto plan_d; } LIST_FOREACH(sctp_ifa, &emit_ifn->ifalist, next_ifa) { + SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifa:%p\n", sctp_ifa); if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && - (non_asoc_addr_ok == 0)) + (non_asoc_addr_ok == 0)) { + SCTPDBG(SCTP_DEBUG_OUTPUT2, "Defer\n"); continue; + } sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, dest_is_priv, fam); - if (sifa == NULL) + if (sifa == NULL) { + SCTPDBG(SCTP_DEBUG_OUTPUT2, "IFA not acceptable\n"); continue; + } if (stcb) { if (sctp_is_address_in_scope(sifa, stcb->asoc.ipv4_addr_legal, @@ -3006,6 +3047,8 @@ bound_all_plan_b: stcb->asoc.ipv4_local_scope, stcb->asoc.local_scope, stcb->asoc.site_scope, 0) == 0) { + SCTPDBG(SCTP_DEBUG_OUTPUT2, "NOT in scope\n"); + sifa = NULL; continue; } if (((non_asoc_addr_ok == 0) && @@ -3017,11 +3060,15 @@ bound_all_plan_b: * It is restricted for some reason.. * probably not yet added. */ + SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its resticted\n"); + sifa = NULL; continue; } + } else { + printf("Stcb is null - no print\n"); } atomic_add_int(&sifa->refcount, 1); - return (sifa); + goto out; } plan_d: /* @@ -3030,16 +3077,12 @@ plan_d: * out and see if we can find an acceptable address somewhere * amongst all interfaces. */ - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan D\n"); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan D looked_at is %p\n", looked_at); LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { /* wrong base scope */ continue; } - if ((sctp_ifn == looked_at) && looked_at) - /* already looked at this guy */ - continue; - LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0)) @@ -3057,6 +3100,7 @@ plan_d: stcb->asoc.ipv4_local_scope, stcb->asoc.local_scope, stcb->asoc.site_scope, 0) == 0) { + sifa = NULL; continue; } if (((non_asoc_addr_ok == 0) && @@ -3068,19 +3112,81 @@ plan_d: * It is restricted for some * reason.. probably not yet added. */ + sifa = NULL; continue; } } - atomic_add_int(&sifa->refcount, 1); - return (sifa); + goto out; } } - /* - * Ok we can find NO address to source from that is not on our - * restricted list and non_asoc_address is NOT ok, or it is on our - * restricted list. We can't source to it :-( - */ - return (NULL); +#ifdef INET + if ((retried == 0) && (stcb->asoc.ipv4_local_scope == 0)) { + stcb->asoc.ipv4_local_scope = 1; + retried = 1; + goto again_with_private_addresses_allowed; + } else if (retried == 1) { + stcb->asoc.ipv4_local_scope = 0; + } +#endif +out: + if (sifa) { +#ifdef INET + if (retried == 1) { + LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { + if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { + /* wrong base scope */ + continue; + } + LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { + struct sctp_ifa *tmp_sifa; + + if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && + (non_asoc_addr_ok == 0)) + continue; + tmp_sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, + dest_is_loop, + dest_is_priv, fam); + if (tmp_sifa == NULL) { + continue; + } + if (tmp_sifa == sifa) { + continue; + } + if (stcb) { + if (sctp_is_address_in_scope(tmp_sifa, + stcb->asoc.ipv4_addr_legal, + stcb->asoc.ipv6_addr_legal, + stcb->asoc.loopback_scope, + stcb->asoc.ipv4_local_scope, + stcb->asoc.local_scope, + stcb->asoc.site_scope, 0) == 0) { + continue; + } + if (((non_asoc_addr_ok == 0) && + (sctp_is_addr_restricted(stcb, tmp_sifa))) || + (non_asoc_addr_ok && + (sctp_is_addr_restricted(stcb, tmp_sifa)) && + (!sctp_is_addr_pending(stcb, tmp_sifa)))) { + /* + * It is restricted + * for some reason.. + * probably not yet + * added. + */ + continue; + } + } + if ((tmp_sifa->address.sin.sin_family == AF_INET) && + (IN4_ISPRIVATE_ADDRESS(&(tmp_sifa->address.sin.sin_addr)))) { + sctp_add_local_addr_restricted(stcb, tmp_sifa); + } + } + } + } + atomic_add_int(&sifa->refcount, 1); + } +#endif + return (sifa); } @@ -3106,7 +3212,7 @@ sctp_source_address_selection(struct sct #endif - /*- + /** * Rules: - Find the route if needed, cache if I can. - Look at * interface address in route, Is it in the bound list. If so we * have the best source. - If not we must rotate amongst the @@ -3509,15 +3615,17 @@ sctp_lowlevel_chunk_output(struct sctp_i ) /* nofragment_flag to tell if IP_DF should be set (IPv4 only) */ { - /* - * Given a mbuf chain (via SCTP_BUF_NEXT()) that holds a packet - * header WITH an SCTPHDR but no IP header, endpoint inp and sa - * structure: - fill in the HMAC digest of any AUTH chunk in the - * packet. - calculate and fill in the SCTP checksum. - prepend an - * IP address header. - if boundall use INADDR_ANY. - if - * boundspecific do source address selection. - set fragmentation - * option for ipV4. - On return from IP output, check/adjust mtu - * size of output interface and smallest_mtu size as well. + /** + * Given a mbuf chain (via SCTP_BUF_NEXT()) that holds a packet header + * WITH an SCTPHDR but no IP header, endpoint inp and sa structure: + * - fill in the HMAC digest of any AUTH chunk in the packet. + * - calculate and fill in the SCTP checksum. + * - prepend an IP address header. + * - if boundall use INADDR_ANY. + * - if boundspecific do source address selection. + * - set fragmentation option for ipV4. + * - On return from IP output, check/adjust mtu size of output + * interface and smallest_mtu size as well. */ /* Will need ifdefs around this */ struct mbuf *o_pak; @@ -4409,7 +4517,7 @@ sctp_send_initiate(struct sctp_inpcb *in scp.local_scope = stcb->asoc.local_scope; scp.site_scope = stcb->asoc.site_scope; - m_at = sctp_add_addresses_to_i_ia(inp, &scp, m_at, cnt_inits_to); + m_at = sctp_add_addresses_to_i_ia(inp, stcb, &scp, m_at, cnt_inits_to); } /* calulate the size and update pkt header and chunk header */ @@ -5538,7 +5646,7 @@ do_a_abort: scp.ipv4_local_scope = stc.ipv4_scope; scp.local_scope = stc.local_scope; scp.site_scope = stc.site_scope; - m_at = sctp_add_addresses_to_i_ia(inp, &scp, m_at, cnt_inits_to); + m_at = sctp_add_addresses_to_i_ia(inp, stcb, &scp, m_at, cnt_inits_to); } /* tack on the operational error if present */ Modified: head/sys/netinet/sctp_output.h ============================================================================== --- head/sys/netinet/sctp_output.h Sat May 14 18:22:08 2011 (r221903) +++ head/sys/netinet/sctp_output.h Sat May 14 18:22:14 2011 (r221904) @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); struct mbuf * sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, + struct sctp_tcb *stcb, struct sctp_scoping *scope, struct mbuf *m_at, int cnt_inits_to);