Bug 62051 - SCTP fails to bind to link-local IPv6 address.
Summary: SCTP fails to bind to link-local IPv6 address.
Status: NEW
Alias: None
Product: Networking
Classification: Unclassified
Component: IPV6 (show other bugs)
Hardware: All Linux
: P1 normal
Assignee: Hideaki YOSHIFUJI
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-09-25 03:46 UTC by Ben Greear
Modified: 2016-02-15 20:11 UTC (History)
3 users (show)

See Also:
Kernel Version: 3.9.11+
Subsystem:
Regression: No
Bisected commit-id:


Attachments

Description Ben Greear 2013-09-25 03:46:09 UTC
It will bind fine to global IPv6 addresses, but not to link-local IPv6
addresses.  I don't have time to track it down now, so opening bug so issue is not totally forgotten.

Code in question looks like this:

int createSctp6Socket(const char* ipv6_addr_string, uint16 ip_port,
                      const char* dev_to_bind_to) {

   return createConnected6Socket(ipv6_addr_string, ip_port, dev_to_bind_to, IPPROTO_SCTP);

}

int createConnected6Socket(const char* ipv6_addr_string, uint16 ip_port,
                           const char* dev_to_bind_to, int proto_type) {

   int aiErr;
   int s = -1;
   struct addrinfo *aiHead;
   struct addrinfo hints;
   memset(&hints, 0, sizeof(hints));

   hints.ai_flags  = AI_NUMERICSERV;
   hints.ai_family = PF_INET6;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_protocol = proto_type;

   char service[40];
   sprintf(service, "%d", (int)(ip_port));

   const char* node = ipv6_addr_string;

   if (( aiErr = getaddrinfo(node, service, &hints, &aiHead)) != 0) {
      VLOG_ERR(VLOG << "ERROR: trying to get addrinfo for ipv6 on port: " << dev_to_bind_to
               << " error: " << gai_strerror(aiErr) << " node: "
               << node << " service: " << service << endl);
      return -1;
   }

   if (aiHead) {
      // Got one..not sure why we'd get multiple..will ignore for now.

      s = lfsocket(aiHead->ai_family, aiHead->ai_socktype, aiHead->ai_protocol);

      if (s < 0) {
         cerr << "ERROR: connected IPv6 socket:  " << LFSTRERROR << endl;
         VLOG << "ERROR: connected IPv6 socket:  " << LFSTRERROR << endl;
         return s;
      }

      close_exec(s);

      reuseaddr_socket(s);

      if (dev_to_bind_to) {
         // Bind to specific device.
#if ! (defined(__WIN32__) || defined(__sun__))
         if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
                        dev_to_bind_to, DEV_NAME_LEN + 1)) {
            VLOG_ERR(VLOG << "ERROR:  tcp-connect, setsockopt (BINDTODEVICE):  "
                     << LFSTRERROR << "  Not fatal in most cases..continuing...\n");
         }
#endif
      }//if 


// Windows doesn't support this it seems.
#ifdef IPV6_V6ONLY
      int v6_only = 1;
      if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &v6_only, sizeof(v6_only))) {
         VLOG_ERR(VLOG << "ERROR:  setsockopt(IPV6_V6ONLY): "
                  << LFSTRERROR << endl);
      }
#endif

      int r = bind(s, aiHead->ai_addr, aiHead->ai_addrlen);
      if (r < 0) {
         VLOG_ERR(VLOG << "ERROR: connected IPv6 bind:  " << LFSTRERROR << "  IP: "
                  << ipv6_addr_string << " ip_ort: " << ip_port
                  << " ai-addr: " << toString((struct sockaddr_in6*)(aiHead->ai_addr))
                  << " ai-addr-len: " << aiHead->ai_addrlen
                  << " ai-socktype: " << (int)(aiHead->ai_socktype)
                  << " ai-protocol: " << (int)(aiHead->ai_protocol)
                  << endl);
         closesocket(s);
         return r;
      }
      else {
         VLOG_INF(VLOG << "Successfully bound connected socket IP6: "
                  << toString((struct sockaddr_in6*)(aiHead->ai_addr)) << " port: "
                  << ip_port << endl);
      }

      nonblock(s, "create tcp6 socket");

   }//if we found one

   freeaddrinfo( aiHead );
   return s;
}
Comment 1 Xin Long 2014-02-11 09:46:27 UTC
the reason is that : sctp_do_bind invoke sctp_inet6_bind_verify(),which have the following limit:
...
                if (type & IPV6_ADDR_LINKLOCAL) {
                        struct net *net;
                        if (!addr->v6.sin6_scope_id)  <===  the limit
                                return 0;
                        net = sock_net(&opt->inet.sk);
                        rcu_read_lock();
                        dev = dev_get_by_index_rcu(net, addr->v6.sin6_scope_id);
                        if (!dev ||
                            !ipv6_chk_addr(net, &addr->v6.sin6_addr, dev, 0)) {
                                rcu_read_unlock();
                                return 0;
                        }
                        rcu_read_unlock();
                } else if (type == IPV6_ADDR_MAPPED) {
...

so it's not a bug , you can workaround it like:
1.add a line: aiHead->ai_addr.sin6_scope_id=3 (3 is the dev's ifindex , you need to know it).

or,
2.getting your sockaddr to bind from getifaddrs(),  which will fill out the scope id for you.

note: sin6_scope_id is net_device's ifindex when sockaddr is link local addr in ipv6.
Comment 2 Aarti Dwivedi 2014-10-21 12:27:13 UTC
@lucien I was wondering if you could point to the easiest way to test this bug.
I am a novice and this is my first try at fixing a bug.
Thanks,
Aarti

 (In reply to lucien from comment #1)
> the reason is that : sctp_do_bind invoke sctp_inet6_bind_verify(),which have
> the following limit:
> ...
>                 if (type & IPV6_ADDR_LINKLOCAL) {
>                         struct net *net;
>                         if (!addr->v6.sin6_scope_id)  <===  the limit
>                                 return 0;
>                         net = sock_net(&opt->inet.sk);
>                         rcu_read_lock();
>                         dev = dev_get_by_index_rcu(net,
> addr->v6.sin6_scope_id);
>                         if (!dev ||
>                             !ipv6_chk_addr(net, &addr->v6.sin6_addr, dev,
> 0)) {
>                                 rcu_read_unlock();
>                                 return 0;
>                         }
>                         rcu_read_unlock();
>                 } else if (type == IPV6_ADDR_MAPPED) {
> ...
> 
> so it's not a bug , you can workaround it like:
> 1.add a line: aiHead->ai_addr.sin6_scope_id=3 (3 is the dev's ifindex , you
> need to know it).
> 
> or,
> 2.getting your sockaddr to bind from getifaddrs(),  which will fill out the
> scope id for you.
> 
> note: sin6_scope_id is net_device's ifindex when sockaddr is link local addr
> in ipv6.

Note You need to log in before you can comment on or make changes to this bug.