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
More correct form of /etc/hosts #27105
Conversation
It adds its contents to '127.0.0.1' line of /etc/hosts It makes possible to point multiple domains to localhost in correct way
@regellosigkeitsaxiom, thanks for your PR! By analyzing the history of the files in this pull request, we identified @edolstra, @Mic92 and @ardumont to be potential reviewers. |
nixos/modules/config/networking.nix
Outdated
@@ -187,11 +199,11 @@ in | |||
"rpc".source = pkgs.glibc.out + "/etc/rpc"; | |||
|
|||
# /etc/hosts: Hostname-to-IP mappings. | |||
"hosts".text = | |||
"hosts".text = let foo = concatStringsSep " " cfg.extraLocalHosts; in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
foo
? Seriously?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What my predecessor meant to say, is that foo
is in general not a good name for a variable as it is too generic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By naming this "variable" foo
I meant that its name does not hold any significance in semantic space of whole program. It is just a technical variable for text that occurs in several (two in this case) places, an its purpose is minor increase in bug-proofness in a way that one will not change this text in one place and forget to do same in the other.
Its scope is limited to several lines, and its use is kinda obvious, so it should not be a problem (except greping source).
It is just a coding style thing, and I do not hold it dear. So if you propose how should be done, it should not be a problem at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good initiative, but careless implementation.
Help me understand: it seems to me the current implementation ensures that the canonical localhost mapping comes first and so always will resolve correctly (unless you override the low-level Can you elaborate? |
Hrm, it occurred to me that you're probably talking about names other than localhost ... EDIT: but then it seems like we're trying to support odd use cases; who would try to map a name to localhost and some other address in the same hosts file configuration? That just seems confused. |
nixos/modules/config/networking.nix
Outdated
'' | ||
127.0.0.1 localhost | ||
127.0.0.1 localhost ${foo} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the article, it might be desirable to have the variable before localhost to set the fqdn correctly.
Maybe the smarter solution is to prepend extraHosts
before the localhost sections. Then there would be no need for an extra option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for correction about FQDN, I will adjust it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As for prepending extraHosts
before localhost, this will cause havoc, as explained in chosen answer of the article.
@joachifm my use case is the following: I sometimes work on web services for which URI's are important, say it connects to socket at fixed address My specific problem is, that if I am connected to network with no Internet connection, accessing second /etc/hosts 127.0.0.1 line hangs. I do not know exactly how this works, but setting up /etc/hosts correctly helps. (I may be missing or distorting some details, but it bugs me nevertheless). |
@volth I agree with you point that extra option for such trivial and rare thing is overkill. However I think that doing it exactly the way you proposed will break config transparency. Main reason is that option is named Simply dropping I suppose that this form should better implement you intention: {
networking.hosts = {
"127.0.0.1" = [ "foo.example.com" ];
"192.168.0.2" = [ "fileserver.local" "nameserver.local" ];
};
} This way it can be trivially and safely merged into /etc/hosts in expected way. |
@regellosigkeitsaxiom would using a higher merge priority work for you? As in, specifying
Then these entries should come immediately after the standard localhost mappings in the resulting hosts file. That'd accomplish the same thing as this new option, right? |
@joachifm if I understood you correctly, resulting file will be:
This will break many things. My aim is to have the file:
|
@regellosigkeitsaxiom no, the current implementation emits |
Removed |
nixos/modules/config/networking.nix
Outdated
default = null; | ||
example = "foo.example.com"; | ||
description = '' | ||
Full qualified domain name, if any. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fully
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no further comments after the details I mentioned have been addressed.
Thanks!
nixos/modules/config/networking.nix
Outdated
then concatStringsSep " " ( filter (x : x != "localhost" ) ( getAttr "::1" cfg.hosts)) | ||
else ""; | ||
otherHosts = allToString ( removeAttrs cfg.hosts [ "127.0.0.1" "::1" ]); | ||
maybeFQDN = if cfg.fqdn == null then "" else cfq.fqdn; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have lib.optionalString
for this.
nixos/modules/config/networking.nix
Outdated
userLocalHosts = | ||
if builtins.hasAttr "127.0.0.1" cfg.hosts | ||
then concatStringsSep " " ( filter (x : x != "localhost" ) ( getAttr "127.0.0.1" cfg.hosts)) | ||
else ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can be also shortened with optionalString
.
nixos/modules/config/networking.nix
Outdated
userLocalHosts6 = | ||
if builtins.hasAttr "::1" cfg.hosts | ||
then concatStringsSep " " ( filter (x : x != "localhost" ) ( getAttr "::1" cfg.hosts)) | ||
else ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here.
Also dangerous typo fix
It seems clear that having the same IP on multiple lines is bad. I don't know these UNIX* details well, but do you have any idea why |
@vcunat will this configuration work for your purpose? {
networking.hostname="foobar";
networking.fqdn = cfg.networking.hostname + ".example.com.";
networking.hosts = {
"93.184.216.34" = [ cfg.networking.fqdn ];
};
} While it might be nice to have options like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems OK.
BTW, we do have |
@volth will resulting If it will be switched by something like I am against including it into this PR as it seems an entirely different feature to me. |
@volth Maybe something like |
What is going on here? Are there comments by @volth missing? I see @regellosigkeitsaxiom answering him but he isn't a participant on this issue. Github bug? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I welcome the change to a more declarative way to specify hosts. 👍
I suppose |
Oh, I am just catching up on this... Can we not deprecate |
@volth: that would result into the file being writable (by root) but overwritten on each activation, right? I wonder what's the use case – is there some SW that wants to write into it? @NeQuissimus: right, adding a list from a (potentially large) file is something we do want to support. I should've noticed. Undeprecating |
@NeQuissimus technically, I submitted #27791 which removes this warning. |
It's not exactly clear to me what this PR does to 127.0.0.1. If it adds a mapping for the hostname, then that's incorrect - that's done automatically via |
@edolstra it makes possible to concatenate all mappings to 127.0.0.1 into one line:
Via
which sometimes leads to problems as /etc/hosts actually works as two-way mapping. This PR ensures that every IP occurs only once, and 127.0.0.1 is treated specially only in a way that it guarantees that it will map to Regarding |
Mapping the FQDN to 127.0.0.1 is very very wrong. For example, consider a web server configuration that tells the server to listen on
|
@edolstra In a sense, it will not "suddenly" listen on 127.0.0.1 as |
@volth in my case I go with If I were in you shoes, I'd try to include into |
It's a fallback because |
I do sometimes remove symlinks in |
@regellosigkeitsaxiom Well, prior to this PR, the FQDN would be looked up in DNS, which would return an address other than 127.0.0.1, assuming the FQDN exists in DNS. BTW, the
Possibly relevant: https://bugzilla.redhat.com/show_bug.cgi?id=530343 In any case, let's not mess with hostname mappings in /etc/hosts since it will have unpredictable results. |
The
The related docs seem to mainly describe the implementation, IMHO, and not the (intended) meaning of it. We can't significantly affect that mess, except perhaps building some clearer abstraction above it. In any case, I believe we should allow changing the 127.0.0.1 + ::1 lines declaratively – adding more aliases (which is what this PR did), even though we may not be recommending to do so. As noted, by default this PR changes nothing. We might perhaps improve the descriptions to better explain what the options do.
|
( builtins.hasAttr "::1" cfg.hosts ) | ||
( concatStringsSep " " ( remove "localhost" cfg.hosts."::1" )); | ||
otherHosts = allToString ( removeAttrs cfg.hosts [ "127.0.0.1" "::1" ]); | ||
maybeFQDN = optionalString ( cfg.fqdn != null ) cfg.fqdn; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it make more sense to put the following into config
instead?
{
networking.hosts = {
"127.0.0.1" = [ "localhost" ];
} // optionalAttrs cfg.enableIPv6 {
"::1" = [ "localhost" ];
};
}
That way the value in environment.etc.hosts.text
can be reduced to:
let
mkEntry = ip: hosts: "${ip} ${concatStringsSep " " hosts}";
in ''
${concatStringsSep "\n" (mapAttrsToList mkEntry cfg.hosts)}
${cfg.extraHosts}
''
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point of much of the fuss in this PR is that the first name after an address has a "special meaning" in /etc/hosts
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still, as the fqdn
option was removed, we might as well simplify the implementation...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vcunat: We could still use mkOrder 900
on [ "localhost" ]
so that users can override it with mkBefore
and mkAfter
, or even go further and change the type of the hosts
option to something like this:
types.attrsOf (submodule {
options.canonical = mkOption { type = types.str; ... };
options.aliases = mkOption { type = types.listOf types.str; ... };
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, right, that would also be a possibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@regellosigkeitsaxiom: A different way to handle this would be the other way around, mapping canonical hostnames to IP addresses. But either way, we can still provide our own merge function instead of the default one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can still provide our own merge function instead of the default one.
This. Although I have no idea how to implement it.
mapping canonical hostnames to IP addresses.
This is good too. Current implementation misses check that no alias mapped to two different IP addresses, but this way it can be done trivially.
In my mind, it looks like this:
{
networking.hosts.aliases = {
"foo.example.com" = "127.0.0.2";
"bar.example.com" = "127.0.0.2";
};
networking.hosts.canonical = {
"foobar.example.com" = "127.0.0.2";
};
}
which will emit 127.0.0.2 foobar.example.com foo.example.com bar.example.com
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is a bit verbose, but let me write an implementation which allows both ways (host -> ip
and ip -> host(s)
)...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw. this already should merge as expected:
$ nix-instantiate nixos --eval --strict --arg configuration '{ imports = [ { networking.hosts."127.0.0.1".canonical = "aaa"; } ]; networking.hosts."127.0.0.1".canonical = "bbb"; }' -A config.networking.hosts
error: The unique option `networking.hosts.127.0.0.1.canonical' is defined multiple times, in `<unknown-file>' and `<unknown-file>'.
(use ‘--show-trace’ to show detailed location information)
$
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #27804.
Thank you @regellosigkeitsaxiom. Generally, deprecated things go away sooner or later, which is why I was concerned when I saw the warning :) We are all good now from what I can tell. |
Makes management of
/etc/hosts
more declarative by usingnetworking.hosts
.Motivation for this change
It makes possible to point multiple domains to
localhost
in correct way: just adding127.0.0.1 localhost.localdomain
tonetworking.extraHosts
will not always work and is incorrect.Things done
(nix.useSandbox on NixOS,
or option
build-use-sandbox
innix.conf
on non-NixOS)
nix-shell -p nox --run "nox-review wip"
./result/bin/
)