Bug 218508 - Tunneling and aliases using the tun device, reusing a destination address works with IPv4, but not IPv6
Summary: Tunneling and aliases using the tun device, reusing a destination address wor...
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 11.0-RELEASE
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-net (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-04-09 08:29 UTC by Christian Sturm
Modified: 2021-02-25 15:39 UTC (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Christian Sturm 2017-04-09 08:29:27 UTC
I can create a tun device by using:

ifconfig tun0 create
ifconfig tun 10.1.2.0 196.2.3.4 
ifconfig tun alias 196.2.3.3 196.2.3.4
ifconfig up

This works great and allows me to use the 10.1.2.0 and have it tunneled over the second (aliased) tunnel when I set up the correct route using /sbin/route add -net 10.0.0.0/8 -iface tun0.

I have this setup, using IPv6 only working as it is supposed to. To explain what I am am actually achieving with this: In the background I am using BGP over a one-to-one VPN software using the tunnel interface.

Doing the same thing on IPv6, however doesn't work when I add an alias, using the same destination address twice:

ifconfig tun0 inet6 fdaa:abc:abc:abc::1 fe80::111:0 prefixlen /128
ifconfig tun0 inet6 alias fe80::111:1 fe80::111:0 prefixlen /128
ifconfig: ioctl (SIOCAIFADDR): File exists

Using another destination address this works however. Since this works on IPv4 I'd expect it to work here as well.
Comment 1 dmilith 2020-07-30 13:40:19 UTC
I have same bug on 12.1… "file exists":

```
socket(PF_INET,SOCK_DGRAM|SOCK_CLOEXEC,0)        = 3 (0x3)
ioctl(3,SIOCGIFINDEX,0x7fffffff9f20)             = 0 (0x0)
close(3)                                         = 0 (0x0)
__sysctl(0x7fffffff9f40,0x6,0x0,0x7fffffff9f38,0x0,0x0) = 0 (0x0)
__sysctl(0x7fffffff9f40,0x6,0x80161e000,0x7fffffff9f38,0x0,0x0) = 0 (0x0)
socket(PF_INET6,SOCK_DGRAM,0)                    = 3 (0x3)
ioctl(3,SIOCDIFADDR_IN6,0x1054278)               ERR#49 'Can't assign requested address'
ioctl(3,SIOCAIFADDR_IN6,0x1054278)               ERR#17 'File exists'
ifconfig: write(2,"ifconfig: ",10)                       = 10 (0xa)
ioctl (SIOCAIFADDR)write(2,"ioctl (SIOCAIFADDR)",19)             = 19 (0x13)
: write(2,": ",2)                                        = 2 (0x2)
File exists
write(2,"File exists\n",12)                      = 12 (0xc)
exit(0x1)
process exit, rval = 1
```
Comment 2 Denton Gentry 2021-02-25 15:39:43 UTC
We've been encountering this in https://github.com/tailscale/tailscale/issues/1307

The problem occurs because rtrequest1_fib returns EEXIST.

root@freebsd12:~ # dtrace -n 'fbt:::return /(int)arg1 == EEXIST / { stack(); }' -c "ifconfig tun0 inet6 fd7a:115c:a1e0:ab12:4843:cd96:625c:1f1b fd7a:115c:a1e0:ab12:4843:cd96:625c:1f1b prefixlen 128"
dtrace: description 'fbt:::return ' matched 29364 probes
ifconfig: ioctl (SIOCAIFADDR): File exists
dtrace: pid 1175 exited with status 1
CPU     ID                    FUNCTION:NAME
  1  52657            rtrequest1_fib:return
              kernel`rtinit+0x421
              kernel`in6_update_ifa+0xc6b
              kernel`in6_control+0x96f
              kernel`ifioctl+0x47f
              kernel`kern_ioctl+0x2b7
              kernel`sys_ioctl+0xfa
              kernel`amd64_syscall+0x387
              kernel`0xffffffff8106785e

That happens because rn_addroute returns NULL:

rn_addroute(void *v_arg, void *n_arg, struct radix_head *head,
    struct radix_node treenodes[2])
...
        /*
         * Deal with duplicated keys: attach node to previous instance
         */
        saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
        if (keyduplicated) {
                for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {
#ifdef RADIX_MPATH
                        /* permit multipath, if enabled for the family */
                        ...
#endif
                        if (tt->rn_mask == netmask)
                                return (0);


There is a bunch of code within the #ifdef RADIX_MPATH block above. Enabling RADIX_MPATH in the kernel config does allow the tun0 address assignment to succeed, though I haven't fully tested if it works as expected.


It looks like this behavior was understood, in a comment in sys/netinet6/in6.c:in6_notify_ifa from 2004:

        /*
         * If a new destination address is specified for a point-to-point
         * interface, install a route to the destination as an interface
         * direct route.
         * XXX: the logic below rejects assigning multiple addresses on a p2p.
         * interface that share the same destination.
         */
        plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
        if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
            ia->ia_dstaddr.sin6_family == AF_INET6) {