I recognized that my laptop does not prefer temporary IPv6 addresses despite it being the default.
As I found out with nixos-option, networking.interfaces.wlp3s0.preferTempAddress is only set to true if there is any mention of the attrs such as networking.interfaces.wlp3s0.name = "wlp3s0". Otherwise it is "missing":
# This is also the case for the 'implicit' test case described below.
$ nixos-option networking.interfaces.wlp3s0.preferTempAddress
Value:
error: attribute 'wlp3s0' missing
Default:
true
...
As I had no mention of the wlp3s0 interface in my config, it was left without IPv6 Privacy Extensions being enabled, which I find to be a bit unintuitive.
I could imagine that this is not easy to fix as NixOS can't know about undeclared networking interfaces at evaluation time, but maybe there could be a clever explanation of it in the manual? Or maybe hardware-config.nix should contain declarations for all networking interfaces found at generation time? Or we set net/ipv6/conf/all/use_tempaddr=2?
Pinging @rnhmjoj, as they introduced the feature in https://github.com/NixOS/nixpkgs/pull/34492.
Run these tests, observe the last one failing:
with import <nixpkgs> {};
lib.mapAttrsToList
(name: module:
import <nixpkgs/nixos/tests/make-test.nix> ({ pkgs, ...}:{
name = "ipv6-use-tempaddr-${name}";
nodes.machine = module;
testScript = ''
$machine->waitForUnit("network.target");
$machine->succeed("ip addr show dev eth0");
# this should work, as use_tempaddr is the default
$machine->succeed("sysctl --values net/ipv6/conf/eth0/use_tempaddr | grep -F '2'");
'';
})
)
{
# this works
explicit = ({ config, pkgs, lib, ... }:{
networking.interfaces.eth0.preferTempAddress = true;
});
# this works also, despite the option being not eplicitly set
implicitWithDefinedAttribute = ({ config, pkgs, lib, ... }:{
networking.interfaces.eth0.name = "eth0";
});
# this works not :(
implicit = ({ config, pkgs, lib, ... }:{
});
}
"x86_64-linux"Linux 4.14.101, NixOS, 18.09 (Jellyfish)yesyesnix-env (Nix) 2.1.3"nixos-hardware, nixos-unstable-19.03pre166449.be445a9074f, nixos-18.03-18.03.133311.5d19e3e78fb""nixos-hardware"/home/justin/nixpkgsI believe it's a regression since 18.09: my Hydra builders run on stable (18.09) and they prefer the short IPv6, and my current box is on unstable and prefers the long one. (Both share DHCP server and don't have explicitly configured interfaces.)
@vcunat My test fails both for nixos-18.09 and nixos-unstable. Did you inspect with nixos-option?
$ nixos-option networking.interfaces
Value:
{ }
Let me increase the severity of this. I find it quite bad if the default setting leaks your MAC address to most servers you communicate with.
I'm not sure around DHCP... maybe the server can affect this as well?
I don't know about my test failing but the option not working for undeclared interfaces is intended.
The linux kernel does have a sysctl option to enable privacy extensions on all interfaces, net.ipv6.conf.all.use_tempaddr, but it doesn't actually work because it only applies to interfaces that have yet to be created. By the time the option it is set all (physical) interfaces have been configured so it has no effect. Unfortunately they won't fix this problem so there is nothing we can do about it besides configuring each interface manually.
See https://bugzilla.kernel.org/show_bug.cgi?id=11655.
Surely there's some good way to use the privacy-friendly default without any explicit config. At least on some of my NixOS machines this seems to work fine by itself (unless I overlooked something).
@rnhmjoj I don't think there is any test failing, I wrote about the test case I provided in the issue.
I see the problem with net.ipv6.conf.all.use_tempaddr. If there is no easy way, maybe the way to go is to generate
...
networking.interfaces = {
wlp3s0 = {};
enp0s25 = {};
};
...
into hardware-configuration.nix?
Actually, on a machine where the short addresses are preferred I still get the same sysctl as on the one preferring the long addresses:
# sysctl net/ipv6/conf | grep use_tempaddr
net.ipv6.conf.all.use_tempaddr = 0
net.ipv6.conf.default.use_tempaddr = 0
net.ipv6.conf.eno1.use_tempaddr = 0
net.ipv6.conf.lo.use_tempaddr = -1
Unfortunately they won't fix this problem se there is nothing we can do about it besides configuring each interface manually.
I guess there is an option of setting the defaults in early initrd before loading the modules. Not sure if it is a good option.
@erictapen I see. The test I meant is nix-build nixos/tests/networking.nix --arg networkd false -A privacy
It's equivalent to your "explicit" variant and it's indeed fine.
Actually, on a machine where the _short_ addresses are preferred I still get the same sysctl as on the one preferring the long addresses:
@vcunat I'm unsure what you mean by short addresses. In my case, temporary as well as dynamic addresses have the same size. I think the important attribute here is temporary:
$ ip addr show dev wlp3s0
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether my:ma:ca:dd:re:ss brd ff:ff:ff:ff:ff:ff
v
inet6 GOODIPV6/64 scope global temporary dynamic
valid_lft 6998sec preferred_lft 978sec
inet6 BADIPV6CONTAININGMYMAC/64 scope global dynamic mngtmpaddr noprefixroute
valid_lft 6998sec preferred_lft 978sec
OK, let me be concrete:
inet6 2a02:768:2208:ed02::d9a/128 scope global noprefixroute
valid_lft forever preferred_lft forever
inet6 2a02:768:2208:ed02:42a8:f0ff:fead:a17b/64 scope global dynamic mngtmpaddr noprefixroute
valid_lft 6837sec preferred_lft 1437sec
I mean, the ::xxx addresses are basically static, yes, but they leak very little information. Leaking whole MAC seems much much worse. Maybe it was bad to mix "two issues" into one.
Perhaps we should set boot.kernel.sysctl."net.ipv6.conf.default.use_tempaddr".
I refined my test, so that it actually checks for temporary addresses on the interface.
with import <nixpkgs> {};
lib.mapAttrsToList
(name: module:
import <nixpkgs/nixos/tests/make-test.nix> ({ pkgs, ...}:{
name = "ipv6-use-tempaddr-${name}";
nodes.machine = module;
testScript = ''
$machine->waitForUnit("network.target");
# this should work, as there should be a temporary address assigned to eth0
$machine->succeed("ip address show dev eth0 temporary | grep temporary");
'';
})
)
{
# this works
explicit = ({ config, pkgs, lib, ... }:{
networking.interfaces.eth0.preferTempAddress = true;
});
# this also works, despite the option being not explicitly set
implicitWithDefinedAttribute = ({ config, pkgs, lib, ... }:{
networking.interfaces.eth0 = {};
});
# this works not :(
default = ({ config, pkgs, lib, ... }:{
boot.kernel.sysctl."net.ipv6.conf.default.use_tempaddr" = 2;
});
# this works not :(
implicit = ({ config, pkgs, lib, ... }:{
});
}
$ nix build -f ipv6-test.nix --keep-going
...
[7 built (2 failed), 0.0 MiB DL]
error: build of '/nix/store/9h81kw8wkwbjllpqgk4picg83bg958ab-vm-test-run-ipv6-use-tempaddr-implicit.drv', '/nix/store/sprqr5jqqpf2bmf0wsr33xh3b7h2dc2c-vm-test-run-ipv6-use-tempaddr-default.drv' failed
@lheckemann Setting boot.kernel.sysctl."net.ipv6.conf.default.use_tempaddr" doesn't solve the issue as seen in the default test. I guess the reason for that is the same @rnhmjoj
explained in https://github.com/NixOS/nixpkgs/issues/56306#issuecomment-466796881.
@vcunat Now I get what you meant with the short addresses. I agree that the short address is not problematic and I guess that it was assigned by DHCPv6 which I have no clue about. However on networks where SLAAC is used for address assignment, one needs a temporary address to have privacy.
I've done a "half-way" fix in the above commit, what might be missing is an option to make it configurable. However, I'd be in favour of just enabling them universally until someone complains that they really need MAC-based SLAAC addresses. Opinions?
That's smart: I didn't consider using udev. In my opinion EUI-64 addresses are just a terrible idea and should only be used for incoming connections but the existing option should be updated to configure that udev rule, though.
I'm not sure how the existing option can be used, since it's interface-specific, while the udev rule covers all interfaces.
Ok, my opinion at this point is that my commit should in fact be merged as is (plus documentation), since the per-interface preferTempAddress defaults to true and can still be disabled on a per-interface basis. I'll open a PR.
@lheckemann Yeah I guess it makes sense to open a PR. If there are any concerns about this particular solution (which I doubt), they would be better discussed there.
Fixed by #62835.
Most helpful comment
Fixed by #62835.