title: How to bind to all addresses of only one network interface (Linux)?
body: <p>What I am trying to achieve is binding an IPv6 socket to any address <em>of just one particular device</em>, not system-wide. My intuition is that I could <code>setsockopt()</code> with <code>SO_BINDTODEVICE</code> followed by a bind to <code>::</code>. It <em>mostly</em> does what I expect it to do. The behaviour is the same in v4.</p>
  
  <p>The sockets bound to an interface with <code>SO_BINDTODEVICE</code> will only accept connections made to addresses on that interface. That much is expected.</p>
  
  <p>However, I run into errno "Address already in use", if I'm trying to bind to a source port on interface B when there is a socket using the same port <em>but</em> on interface A.</p>
  
  <p>Ex:</p>
  
  <ul>
  <li>nic A has IPv6  fd00:aaaa::a/64</li>
  <li>nic B has IPv6  fd00:bbbb::b/64</li>
  <li>they do not share networks.</li>
  </ul>
  
  <p><strong>Put shortly (pseudocode):</strong> </p>
  
  <ul>
  <li>process 1 calls <code>socket(...)</code> and binds <code>bind(fd00:aaaa::a/64, 9000)</code>.</li>
  <li>process 2 calls <code>socket(...)</code> and <code>setsockopt(SO_BINDTODEVICE, "B")</code></li>
  <li>process 2 (continued) calls <code>bind(::, 9000)</code> and gets <code>EADDRINUSE</code>. Why?</li>
  </ul>
  
  <p>How does <code>SO_BINDTODEVICE</code> really work? Does the determination for "addresses in use" ignore, conservatively, the interface sockets are bound to? Is it a networking stack layering issue?</p>
  
  <p><strong>Example traces:</strong></p>
  
  <ol>
  <li>I start a listening socket (server) on a specific address: <code>nc -l fd00:aaaa::a 9000</code>. Its trace is as follows:</li>
  </ol>
  
  <pre class="lang-c prettyprint-override"><code>socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP) = 3
  setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
  bind(3, {
      sa_family=AF_INET6,
      sin6_port=htons(9000),
      inet_pton(AF_INET6, "fd00:aaaa::a", &amp;sin6_addr),
      sin6_flowinfo=0, sin6_scope_id=0
  }, 28) = 0
  listen(3, 1)                            = 0
  accept(3, ...
  </code></pre>
  
  <ol start="2">
  <li>Connecting to it (client) fails if I bind to the port in use by the other interface, even though I've already bound to a different interface:</li>
  </ol>
  
  <pre class="lang-c prettyprint-override"><code>socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 3
  setsockopt(3, SOL_SOCKET, SO_BINDTODEVICE, "nicB\0", 5) = 0
  bind(3, {sa_family=AF_INET6,
           sin6_port=htons(9000),
           inet_pton(AF_INET6, "::", &amp;sin6_addr), 
           sin6_flowinfo=0,
           sin6_scope_id=0
          }, 28) = -1 //EADDRINUSE (Address already in use)
  </code></pre>
  
  <ol start="3">
  <li>However, if I don't specify the port, then all is good when binding to <code>::</code> (while the listener still runs):</li>
  </ol>
  
  <pre class="lang-c prettyprint-override"><code>socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 3
  setsockopt(3, SOL_SOCKET, SO_BINDTODEVICE, "nicB\0", 5) = 0
  bind(3, {
      sa_family=AF_INET6,
      sin6_port=htons(0),
      inet_pton(AF_INET6, "::", &amp;sin6_addr),
      sin6_flowinfo=0, sin6_scope_id=0
  }, 28) = 0
  connect(3, {
      sa_family=AF_INET6,
      sin6_port=htons(9000),
      inet_pton(AF_INET6, "fd00:aaaa::a", &amp;sin6_addr),
      sin6_flowinfo=0, sin6_scope_id=0
  }, 28) = ...
  </code></pre>
  
  <p><em>Note: This is on 3.19.0-68-generic x86_64 . Ubuntu 14.04. In case it makes a difference, for my tests, nicB is a macvlan in bridge mode whose parent is nicA.</em></p>