Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make AdvRASrcAddress accept any link local addresses when net.ipv6.ip_nonlocal_bind=1 #163

Open
jackyzy823 opened this issue Dec 12, 2021 · 1 comment

Comments

@jackyzy823
Copy link

current AdvRASrcAddress will only be used when matched one of valid link local addresses.

if (0 == memcmp(&cmp_addr, &current->address, sizeof(struct in6_addr))) {

I hope that when sysctl net.ipv6.ip_nonlocal_bind=1 is set, AdvRASrcAddress can directly set iface->props.if_addr_rasrc whatever it is a valid link local addresses or not .

Reason:
It maybe a rare case . My VPS provider offers an IPv6 Prefix to a machine. I want to set SLAAC in that machine.

when i use normal radvd.conf ,I can get an IPv6 address , but i must set a gateway manually to fe80::1 to make the connection work. (maybe related to https://serverfault.com/a/1069528).
Because the RA message is sent in the just same machine to itself , so it takes self link local address as gateway.

interface eth0
{
        AdvSendAdvert on;
        MinRtrAdvInterval 30;
        MaxRtrAdvInterval 100;
        prefix <PREFIX1>::/64
        {
                AdvOnLink on;
                AdvAutonomous on;
                AdvRouterAddr off;
        };
        RDNSS  <DNS1>
        {
        };
};

Then I found AdvRASrcAddress option , but when i set AdvRASrcAddress { fe80::1 ; }; , radvd refuse to work saying interface eth0 does not exist or is not set up properly, ignoring the interface because of no configured AdvRASrcAddress present, skipping send.

Finally, I tried short circuit the code and set sysctl net.ipv6.ip_nonlocal_bind=1

diff --git a/device-common.c b/device-common.c
index 77a9e77..46d5316 100644
--- a/device-common.c
+++ b/device-common.c
@@ -179,6 +179,8 @@ int setup_iface_addrs(struct Interface *iface)
                        for (struct AdvRASrcAddress *current = iface->AdvRASrcAddressList; current; current = current->next) {
                                for (int i = 0; i < iface->props.addrs_count; i++) {
                                        struct in6_addr cmp_addr = iface->props.if_addrs[i];
+                                       iface->props.if_addr_rasrc = &current->address;
+                                       break;
                                        if (0 == memcmp(&cmp_addr, &current->address, sizeof(struct in6_addr))) {
                                                addrtostr(&(cmp_addr), addr_str, sizeof(addr_str));
                                                dlog(LOG_DEBUG, 4, "AdvRASrcAddress selecting: %s", addr_str);

And it works. I can do SLAAC and the gateway is fe80::1 and connection works.

@stappersg stappersg removed their assignment Dec 12, 2021
@robbat2
Copy link
Member

robbat2 commented Dec 15, 2021

That's a creative solution, but I have a better suggestion, borrowed from HAProxy's transparent option:
Foreign sockets
IPV6_TRANSPARENT (Linux) / IP_FREEBIND (Linux,FreeBSD?) / IPV6_BINDANY (NetBSD,FreeBSD?) / SO_BINDANY (OpenBSD)

https://github.com/haproxy/haproxy/blob/6dfbef4145845a421e5d9301e26cbc7136d20965/src/sock_inet.c#L246-L267

This would be set as a configuration option, per-interface, and then the kernel should just accept the values set, and permit it on a per-interface basis, which is safer than the sysctl, and more portable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants