Can I create a user-specific hosts file to complement /etc/hosts?
Solution 1
The functionality you are looking for is implemented in glibc. You can define a custom hosts file by setting the HOSTALIASES
environment variable. The names in this file will be picked up by gethostbyname
(see documentation).
Example (tested on Ubuntu 13.10):
$ echo 'g www.google.com' >> ~/.hosts
$ export HOSTALIASES=~/.hosts
$ wget g -O /dev/null
Some limitations:
-
HOSTALIASES
only works for applications usinggetaddrinfo(3)
orgethostbyname(3)
- For setuid/setgid/setcap applications, libc sanitizes the environment, which means that the
HOSTALIASES
setting is lost. ping is setuid root or is given thenet_raw
capability upon execution (because it needs to listen for ICMP packets), soHOSTALIASES
will not work withping
unless you're already root before you callping
.
Solution 2
Beside the LD_PRELOAD
tricks. A simple alternative that may work on a few systems would be to binary-edit a copy of the system library that handles hostname resolution to replace /etc/hosts
with a path of your own.
For instance, on Linux:
If you're not using nscd
, copy libnss_files.so
to some location of your own like:
mkdir -p -- ~/lib &&
cp /lib/x86_64-linux-gnu/libnss_files.so.2 ~/lib
(the shared library may be located elsewhere, e.g. /lib/libnss_files.so.2
)
Now, binary-edit the copy to replace /etc/hosts
in there to something the same length like /tmp/hosts
.
perl -pi -e 's:/etc/hosts:/tmp/hosts:g' ~/lib/libnss_files.so.2
Edit /tmp/hosts
to add the entry you want. And use
export LD_LIBRARY_PATH=~/lib
for nss_files
to look in /tmp/hosts
instead of /etc/hosts
.
Instead of /tmp/hosts
, you could also make it /dev/fd//3
(here using two slashes so that the length of /dev/fd//3
is the same as that of /etc/hosts
), and do
exec 3< ~/hosts
For instance which would allow different commands to use different hosts
files.
If nscd
is installed and running, you can bypass it by doing the same trick, but this time for libc.so.6
and replace the path to the nscd socket (something like /var/run/nscd/socket
) with some nonexistent path.
Solution 3
Private mountspaces created with the unshare
command can be used to provide
a private /etc/hosts file to a shell process and any subsequent child processes started from that shell.
# Start by creating your custom /etc/hosts file
[user] cd ~
[user] cat >my_hosts <<EOF
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
127.0.0.1 news.bbc.co.uk
EOF
[user] sudo unshare --mount
# We're now running as root in a private mountspace.
# Any filesystem mounts performed in this private mountspace
# are private to this shell process and its children
# Use a bind mount to install our custom hosts file over /etc/hosts
[root] mount my_hosts /etc/hosts --bind
[root] cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
127.0.0.1 news.bbc.co.uk
[root] exec su - appuser
[appuser] # Run your app here that needs a custom /etc/hosts file
[appuser] ping news.bbc.co.uk
PING news.bbc.co.uk (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.026 ms
^C
--- news.bbc.co.uk ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.026/0.044/0.062/0.018 ms
Solution 4
I faced the same need, so I tried libnss-userhosts, but it fails at multithreaded applications. Therefore I have written libnss-homehosts. It's very new and tested only by me. You may give a chance for it! It supports some options in /etc/host.conf, multiple alias names, and reverse resolving (address to name).
Solution 5
One solution is to have each user in a separate chroot
, so they can each have a separate /etc/hosts
to themselves.
Related videos on Youtube
Fantastory
Updated on September 18, 2022Comments
-
Fantastory almost 2 years
Is it possible to add a list of hosts that are only specific to a certain user? Perhaps a user-specific hosts file?
This mechanism should also complement the entries in the
/etc/hosts
file.-
SF. over 10 yearswell, you might instead run own nameservers, and have the user use different nameservers per user-specific resolv.conf - except creating user-specific resolv.conf appears to be exactly as difficult as making user-specific /etc/hosts.
-
aaiezza almost 8 yearsIf the server is remote, you might try the ~/.ssh/config file: this post.
-
-
Nick about 11 yearsIf you're interesting specifically in the SSH case, you should see
man ssh_config
. -
fche almost 11 years+1 for audacity, -1 for the shock value
-
Stéphane Chazelas about 10 yearsNote that it doesn't work if you're using
nscd
and is limited to hostnames without a dot. -
Parthian Shot about 9 years+1 for binary patching, -1 for security implications
-
Parthian Shot about 9 yearsWell... yeah, it's doable. Although chrooting is a pretty heavy-duty solution for this kind of thing. And brings with it its own set of issues.
-
Stéphane Chazelas about 9 years@ParthianShot, what security implications?
-
Parthian Shot about 9 years@StéphaneChazelas Changing
LD_LIBRARY_PATH
to point to a directory owned by the user means any other process run by the user can use that directory to co-opt any new processes spawned by replacing libraries. And updates tolibnss_files.so
through the package manager (including security updates) won't be reflected in the patched version. ModifyingLD_LIBRARY_PATH
is generally a bad thing to recommend for other reasons, but it's also unwise because of those issues. -
Stéphane Chazelas about 9 years@ParthianShot, your point about missing updates is a fair point. However, for your other point, if a rogue software is running in your name, it having write access to an area in $LD_LIBRARY_PATH would be the least of your worries as it's already got write access to a lot worse and more reliable areas like your .bash*, crontab, .forward, and all configuration files by all the software you use (where it can for instance set LD_{PRELOAD,LIBRARY_PATH} but would typically do a lot worse)
-
kbolino over 8 yearsThis doesn't seem to work on CentOS 6
-
killermist over 8 yearsWait. I thought mount just mounted filesystems onto directories (mount points). I didn't know that a file could be mounted onto another file. Does that really work? (I am asking that seriously. That isn't sarcasm.)
-
frielp over 8 yearsYep, it works, you can mount a file over another file with --bind.
-
Nuri Hodges over 7 yearsLate to the party, but this is the inverse of what is desired, isn't it? I think OP is looking for a similar solution to adding host-resolving entries to /etc/hosts, but one that can be done in userland without escalated privileges. (i.e.
127.0.0.1 somedomain.com
) -
user991710 over 7 yearsYou do not have to log out and back in again to reload
~/.bashrc
, simply dosource ~/.bashrc
. -
einpoklum almost 7 yearsThis seems like a good idea to pitch to the libnss maintainers and/or to distribution maintainers. But before that happens, users without root themselves will not be able to use it. Still, +1
-
Pryftan over 6 yearsJust as a note to those curious: this is to do with namespaces; there are the syscalls
unshare(2)
andclone(2)
that is part of the magic here. See alsonamespaces(7)
anduser_namespaces(7)
. -
Pryftan over 6 yearsI don't remember then but these days ping isn't a suid binary in Linux; it uses capabilities. If you run
getcap /usr/sbin/ping
you might see something like:/usr/bin/ping = cap_net_admin,cap_net_raw+p
. And technically it's that it needs to open a raw socket rather than ICMP (but I suppose you could argue that's just semantics). -
Nakilon over 5 yearsDespite the man says "the alias file pointed to by HOSTALIASES will first be searched for name" the priority is random and if run this wget example a dozen of times it goes wrong.
-
Qinsi almost 5 yearsCan git or wget use this "resolve"? Or just your function who use function "resolve"?
-
Peter Dotchev almost 5 yearsDoes not work on MacOS :(
-
micahscopes over 4 yearsThis is really cool!
-
stefanct about 4 yearsWhile it can be really helpful, user namespaces are also a big security risks as numerous exploits in the last years have shown. This is not used above (ie you need sudo rights) but should be mentioned. Debian has disabled them on default. One other thing that should also be considered is that to use
unshare
you have to execute/fork another process. Thus it is not completely trivial to implant it in a shell script for automation. One way is to pass the whole code intosh -c
as argument ofunshare
as explained here: piware.de/2012/12/… -
Nicolai almost 4 years@bandie your tool works perfect on my Linux. Do you know any similar solution for MacOS?
-
bandie almost 4 years@Nicolai, unfortunately no. does not MacOS have libnss? if so, libnss-homehost can be ported to.
-
Admin about 2 years@StéphaneChazelas Any idea why it would work with
LD_PRELOAD
but not withLD_LIBRARY_PATH
? Here's what I am running on shell: paste.ee/r/KE1Hl -
Admin about 2 years@BerkantIpek, it's likely a
libnss_files.so.2
filegetent
is looking for, notlibnss_files.so
. Check withLD_DEBUG=libs getent hosts
-
Admin about 2 years
HOSTALIASES
only works for names without any dots -- see__res_context_search()