3

On Linux, I want that a particular process should resolve host "xyz.com" to IP "10.1.2.3". That's easy: just add a line to /etc/hosts.

However, I only want to do this for one process; I want all other processes to resolve "xyz.com" to the DNS.

Is there a way to set a per process resolv.conf or /etc/hosts? I can do this for, e.g., the shared libs or for envariables -- how can I do this for DNS?

SRobertJames
  • 221
  • 4
  • 8

7 Answers7

5

Assuming you have support for network namespaces, iproute2 and iptables, you can accomplish this. Firstly you would want to create a namespace

ip netns add NETNS

and add your custom host file to the directory /etc/netns/NETNS/ (you would need to create this directory)

You would then want to create a virtual ethernet pair to connect the newly created namespace with the main namespace, and configure the interfaces

ip link add veth0 type veth peer name veth1
ip link set veth0 up
ip addr add 172.16.1.0/31 dev veth0
ip netns exec NETNS ip link set lo up
ip netns exec NETNS ip link set veth1 up
ip netns exec NETNS ip addr add 172.16.1.1/31 dev veth1
ip netns exec NETNS ip route add default via 172.16.1.0

and enable the forwarding of IPv4 packets

sysctl net.ipv4.ip_forward=1

and configure the SNAT

iptables -t nat -A POSTROUTING -s 172.16.1.1 -j MASQUERADE

You can then run any command within the network namespace

ip netns exec NETNS COMMAND
Torin
  • 462
  • 1
  • 3
  • 7
3

Mount namespace and override file(s) for a process. Kerr's answer is good but may require root. Bubblewrap is a tool to use mount namespace without root.

bwrap --dev-bind / / --ro-bind-data {FD} /etc/hosts sh -c "command args"

FD is the file descriptor that points to the file containing the content your want to present to the process. (Or, use --bind or --ro-bind instead of --ro-bind-data)

garywill
  • 31
  • 1
2

First:

Ask yourself what you're really trying to accomplish here. This is a very non-standard request that basic tooling isn't prepared to handle. Your basic Linux DNS resolver uses a global configuration (That you already know about in /etc/resolv.conf) and you can't really change that per NIC, or domain, or process, or connection.

See if you can design something simpler to achieve the same end result. Future-you will thank present-you

If you're still reading:

Go back up and read the first section again.

Still here?

Every fiber of my being is hating itself for what I'm about to suggest.

You can use iptables rules that are specific to a process and then redirect DNS traffic accordingly. You could run a separate DNS server on an alternate local port that responds to the domain that you're interested in changing responses for. This should be relatively trivial with dnsmasq.

Wesley
  • 32,690
  • 9
  • 82
  • 117
0

Here is how I override hostname resolution for a single command, without any root access, using the built-in Linux unshare command. I need to use this kind of technique when running FlexLM commands such as lmutil because of their crazy network-name requirements:

tmpdir=$(mktemp -d)

# Here, we create the custom 'hosts' file.
# Replace '1.2.3.4' with the IP,
# Replace 'myserver' with the hostname:
echo '1.2.3.4 myserver' >$tmpdir/hosts

unshare -Urm bash <<END
    mount --bind $tmpdir /etc
    lmutil    # REPLACE WITH YOUR COMMAND
END

rm -rf "$tmpdir"
likebike
  • 101
  • 1
0

There is a way to do this, systemd does it for the /tmp directory if PrivateTmp is set to yes. But I didn't find details on how to implement it in your own processes for different files. You may want to look at the systemd source for ProvateTmp.

RalfFriedl
  • 3,108
  • 4
  • 13
  • 17
0

Your question if essentially “how can I make a single command see a different version of a file”

The answer in Linux is a filesystem namespace. You can use the unshare command to launch a new session which has an independent filesystem hierarchy. You can then use mount -o bind /etc/hosts-special /etc/hosts, and then run your command.

This is occasionally very useful (eg have an installer use /dev/urandom instead of /dev/random so it doesn’t starve from entropy without making any changes to the system). To see that in action: https://distracted-it.blogspot.com/2017/03/installer-or-command-that-hangs-use.html

This is something that Docker does nicely for you; perhaps a better way of solving your problem is to put your problem into a container.

Cameron Kerr
  • 4,069
  • 19
  • 25
0

In your case, instead of messing with complicated network settings, I would move that process in an LXC container, and inside that container I could edit /etc/hosts however I want. LXD/LXC is lightweight and shouldn't cause much overhead.

nva
  • 1
  • 1