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.
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.
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 using getaddrinfo(3)
or gethostbyname(3)
HOSTALIASES
setting is lost. ping is setuid root or is given the net_raw
capability upon execution (because it needs to listen for ICMP packets), so HOSTALIASES
will not work with ping
unless you're already root before you call ping
.nscd
and is limited to hostnames without a dot.
Commented
May 29, 2014 at 12:45
127.0.0.1 somedomain.com
)
Commented
Nov 10, 2016 at 18:53
HOSTALIASES
only works for names without any dots -- see __res_context_search()
Commented
Jun 28, 2022 at 3:58
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.
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 to libnss_files.so
through the package manager (including security updates) won't be reflected in the patched version. Modifying LD_LIBRARY_PATH
is generally a bad thing to recommend for other reasons, but it's also unwise because of those issues.
Commented
Jun 28, 2015 at 3:26
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
unshare(2)
and clone(2)
that is part of the magic here. See also namespaces(7)
and user_namespaces(7)
.
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 into sh -c
as argument of unshare
as explained here: piware.de/2012/12/…
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).
One solution is to have each user in a separate chroot
, so they can each have a separate /etc/hosts
to themselves.
Placing the following in ~/.bashrc
is working for me in bash. It converts the hostname in the command into an address based on entries in ~/.hosts
. If ~/.hosts
doesn't exist or if the hostname can't be found in ~/.hosts
, the command executes as normal. This should work with the original flags of the relevant functions and regarless of where the hostname is placed relative to the flags, e.g. ping -i 0.5 host1 -c 3
, works. The ~/.hosts
file takes preference over any other location for finding hostnames, so if there are any dupicate hostnames, the address in ~/.hosts
will be used.
$ cat ~/.bashrc
function resolve {
hostfile=~/.hosts
if [[ -f "$hostfile" ]]; then
for arg in $(seq 1 $#); do
if [[ "${!arg:0:1}" != "-" ]]; then
ip=$(sed -n -e "/^\s*\(\#.*\|\)$/d" -e "/\<${!arg}\>/{s;^\s*\(\S*\)\s*.*$;\1;p;q}" "$hostfile")
if [[ -n "$ip" ]]; then
command "${FUNCNAME[1]}" "${@:1:$(($arg-1))}" "$ip" "${@:$(($arg+1)):$#}"
return
fi
fi
done
fi
command "${FUNCNAME[1]}" "$@"
}
function ping {
resolve "$@"
}
function traceroute {
resolve "$@"
}
An example of ~/.hosts
is given below. It follows the same format as /etc/hosts
. Comments and whitespace are handled correctly.
$ cat ~/.hosts
# addresses and hostnames
stackexchange.com se
192.168.0.1 host1 # this is host1's address
login-node.inst.ac.uk login
Not sure if this would help you, but I came here looking for a way to add saved "hosts" somewhere that was easily accessible to only my user.
I basically needed to be able to ssh into certain boxes on our work network, which only has one entry point.
What I did was add aliases to my .bashrc
file.
For example, if you added:
alias jrfbox='ssh [email protected]'
at the bottom of your ~/.bashrc
(~
is your home directory). Then after you logout and login again, you can type jrfbox
, hit Enter, and it will connect.
man ssh_config
.
~/.bashrc
, simply do source ~/.bashrc
.
Commented
Mar 2, 2017 at 8:51
It is possible to override dns resolution in google chrome in windows, mac and linux without root/admin access. All we need to do is to start google chrome process with a switch and supply the required DNS entries there.
May be you can append the switch to the shortcut of google chrome in windows or softlink of google chrome in linux so that it varies for each user.
https://devopslife.io/resolve-dns-locally-using-google-chrome/
Here is a way to run the answer by frielp in a script
#!/bin/sh
set -e
# call this file through unshare in a way that keeps normal stdin, $0, and CLI args
sudo unshare -uim sh -c "$(tail -n +7 $0)" "$0" "$@"
exit $?
# unshared program starts here
set -e
echo "mounting my_hosts file as /etc/hosts"
sudo mount my_hosts /etc/hosts --bind
su - khalfani-tmp bash -c "ping new.host.com"
echo "done"