lkml.org 
[lkml]   [2017]   [Jun]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 09/53] sctp: fix src address selection if using secondary addresses for ipv6
    Date
    4.4-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Xin Long <lucien.xin@gmail.com>


    [ Upstream commit dbc2b5e9a09e9a6664679a667ff81cff6e5f2641 ]

    Commit 0ca50d12fe46 ("sctp: fix src address selection if using secondary
    addresses") has fixed a src address selection issue when using secondary
    addresses for ipv4.

    Now sctp ipv6 also has the similar issue. When using a secondary address,
    sctp_v6_get_dst tries to choose the saddr which has the most same bits
    with the daddr by sctp_v6_addr_match_len. It may make some cases not work
    as expected.

    hostA:
    [1] fd21:356b:459a:cf10::11 (eth1)
    [2] fd21:356b:459a:cf20::11 (eth2)

    hostB:
    [a] fd21:356b:459a:cf30::2 (eth1)
    [b] fd21:356b:459a:cf40::2 (eth2)

    route from hostA to hostB:
    fd21:356b:459a:cf30::/64 dev eth1 metric 1024 mtu 1500

    The expected path should be:
    fd21:356b:459a:cf10::11 <-> fd21:356b:459a:cf30::2
    But addr[2] matches addr[a] more bits than addr[1] does, according to
    sctp_v6_addr_match_len. It causes the path to be:
    fd21:356b:459a:cf20::11 <-> fd21:356b:459a:cf30::2

    This patch is to fix it with the same way as Marcelo's fix for sctp ipv4.
    As no ip_dev_find for ipv6, this patch is to use ipv6_chk_addr to check
    if the saddr is in a dev instead.

    Note that for backwards compatibility, it will still do the addr_match_len
    check here when no optimal is found.

    Reported-by: Patrick Talbert <ptalbert@redhat.com>
    Signed-off-by: Xin Long <lucien.xin@gmail.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    net/sctp/ipv6.c | 46 +++++++++++++++++++++++++++++-----------------
    1 file changed, 29 insertions(+), 17 deletions(-)

    --- a/net/sctp/ipv6.c
    +++ b/net/sctp/ipv6.c
    @@ -239,12 +239,10 @@ static void sctp_v6_get_dst(struct sctp_
    struct sctp_bind_addr *bp;
    struct ipv6_pinfo *np = inet6_sk(sk);
    struct sctp_sockaddr_entry *laddr;
    - union sctp_addr *baddr = NULL;
    union sctp_addr *daddr = &t->ipaddr;
    union sctp_addr dst_saddr;
    struct in6_addr *final_p, final;
    __u8 matchlen = 0;
    - __u8 bmatchlen;
    sctp_scope_t scope;

    memset(fl6, 0, sizeof(struct flowi6));
    @@ -311,23 +309,37 @@ static void sctp_v6_get_dst(struct sctp_
    */
    rcu_read_lock();
    list_for_each_entry_rcu(laddr, &bp->address_list, list) {
    - if (!laddr->valid)
    + struct dst_entry *bdst;
    + __u8 bmatchlen;
    +
    + if (!laddr->valid ||
    + laddr->state != SCTP_ADDR_SRC ||
    + laddr->a.sa.sa_family != AF_INET6 ||
    + scope > sctp_scope(&laddr->a))
    continue;
    - if ((laddr->state == SCTP_ADDR_SRC) &&
    - (laddr->a.sa.sa_family == AF_INET6) &&
    - (scope <= sctp_scope(&laddr->a))) {
    - bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
    - if (!baddr || (matchlen < bmatchlen)) {
    - baddr = &laddr->a;
    - matchlen = bmatchlen;
    - }
    - }
    - }
    - if (baddr) {
    - fl6->saddr = baddr->v6.sin6_addr;
    - fl6->fl6_sport = baddr->v6.sin6_port;
    +
    + fl6->saddr = laddr->a.v6.sin6_addr;
    + fl6->fl6_sport = laddr->a.v6.sin6_port;
    final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
    - dst = ip6_dst_lookup_flow(sk, fl6, final_p);
    + bdst = ip6_dst_lookup_flow(sk, fl6, final_p);
    +
    + if (!IS_ERR(bdst) &&
    + ipv6_chk_addr(dev_net(bdst->dev),
    + &laddr->a.v6.sin6_addr, bdst->dev, 1)) {
    + if (!IS_ERR_OR_NULL(dst))
    + dst_release(dst);
    + dst = bdst;
    + break;
    + }
    +
    + bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
    + if (matchlen > bmatchlen)
    + continue;
    +
    + if (!IS_ERR_OR_NULL(dst))
    + dst_release(dst);
    + dst = bdst;
    + matchlen = bmatchlen;
    }
    rcu_read_unlock();


    \
     
     \ /
      Last update: 2017-06-12 00:30    [W:4.290 / U:0.320 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site