resolv/resolv.h: allow alternative resolv.conf files

Message ID 20170817115013.sepjn4aqfi3dlwje@cs.unibo.it
State New, archived
Headers

Commit Message

Renzo Davoli Aug. 17, 2017, 11:50 a.m. UTC
  In network namespaces (like vdens https://github.com/rd235/vdens) it is sometimes necessary to
define per-namespace resolver configurations.

The simple patch here attached permits the definition of an environment variabile to define the
path of the file to use instead of /etc/resolv.conf.

e.g.:
export PATH_RESCONF=/tmp/resolv.conf

2017-08-17 Renzo Davoli <renzo@cs.unibo.it>
  

Comments

Florian Weimer Aug. 17, 2017, 12:41 p.m. UTC | #1
On 08/17/2017 01:50 PM, Renzo Davoli wrote:
> In network namespaces (like vdens https://github.com/rd235/vdens) it is sometimes necessary to
> define per-namespace resolver configurations.
> 
> The simple patch here attached permits the definition of an environment variabile to define the
> path of the file to use instead of /etc/resolv.conf.

_PATH_RESCONF really has to be a string literal, and you can't use a GNU
C extension in such a way in an installed header file.

The environment variable would have to be ignored in AT_SECURE mode, so
you have to use __libc_secure_getenv or put it into unsecvars.h.

I'm still not convinced that this is the right thing to do.  Can you
share more about your use case?  I would expect that containers already
provide sufficient flexibility to adjust what is in /etc/resolv.conf.

Thanks,
Florian
  
Zack Weinberg Aug. 17, 2017, 1:14 p.m. UTC | #2
On Thu, Aug 17, 2017 at 8:41 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 08/17/2017 01:50 PM, Renzo Davoli wrote:
>> In network namespaces (like vdens https://github.com/rd235/vdens) it is sometimes necessary to
>> define per-namespace resolver configurations.
>>
>> The simple patch here attached permits the definition of an environment variabile to define the
>> path of the file to use instead of /etc/resolv.conf.
>
> _PATH_RESCONF really has to be a string literal, and you can't use a GNU
> C extension in such a way in an installed header file.
>
> The environment variable would have to be ignored in AT_SECURE mode, so
> you have to use __libc_secure_getenv or put it into unsecvars.h.
>
> I'm still not convinced that this is the right thing to do.  Can you
> share more about your use case?  I would expect that containers already
> provide sufficient flexibility to adjust what is in /etc/resolv.conf.

'ip netns exec NAMESPACE PROGRAM...' overlay-mounts
/etc/netns/NAMESPACE over /etc, I thought that was the Official
Convention for this sort of thing.

zw
  
Renzo Davoli Aug. 17, 2017, 1:58 p.m. UTC | #3
> Can you share more about your use case?

Sure. I am a developer of VDE, Virtual Distributed Ethernet.

One of the main features of the new implementation (VDE4) are the vde namespaces.
(user namespaces, also for users not having root access).

Simply typing vdens and a VDE-locator of a network a user gets a new namespace
connected to that network.

So for example:
  $ vdens vxvde://
  $ ip addr
  1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
      link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  2: vde0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
      link/ether 02:ef:ba:21:82:5a brd ff:ff:ff:ff:ff:ff
  
Users can configure their ip addresses, routing and use their favourite tools (both
		servers and clients).

As a complete example let us create a vde namespace connected to a remote slirp service:
  $ vdens cmd://'ssh vdetest.v2.cs.unibo.it vde_plug slirp://'
  $ /sbin/udhcpc -i vde0
  udhcpc (v1.22.1) started
  Sending discover...
  Sending select for 10.0.2.15...
  Lease of 10.0.2.15 obtained, lease time 86400
  $ ip link set lo up
  1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
      link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
		  inet 127.0.0.1/8 scope host o
		  valid_lft forever preferred_lft forever
		  inet6 ::1/128 scope host 
		  valid_lft forever preferred_lft forever
  2: vde0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
      link/ether 7e:20:6e:12:f3:ee brd ff:ff:ff:ff:ff:ff
		  inet 10.0.2.15/24 brd 10.0.2.255 scope global vde0
		  valid_lft forever preferred_lft forever
		  inet6 fe80::7c20:6eff:fe12:f3ee/64 scope link 
		  valid_lft forever preferred_lft forever

Now a user can start any server or client... but if the nameserver defined in /etc/resolvconf (by root)
is not reachable all the resolv functions will fail. 

Why a user (not root) should not be allowed to choose her own resolver?
Why to obtain a so simple feature should I have to overlay mount /etc?

I have had the same problem in other project:
* libvdestack: provide processes their own netwoking stack(s)
https://github.com/rd235/libvdestack

* fqdndhcp: a dhcp server receiving the fully qualified domain name from the client and providing
it with the IP(v6) address retrieved fron a DNS server. In this way configuring hosts is as simple as
giving them a name. In this case it happens that sometimes specific DNS servers for the service get used, so
the daemon has to query them instead of the standard servers. I have currently solved this problem using libadns,
but all I needed was a way to use getaddrinfo using my own nameserver.
(see: https://github.com/rd235/vde_dnsutils/blob/master/resolv.c).

Any implementation/alternative approach/patch which fits the requirements (possibility to define the nameserver to use, 
no root access required) is okay to me.

Thank you.

	renzo
  
Florian Weimer Sept. 18, 2017, 3:12 p.m. UTC | #4
My main concern at this point is that a lot of software hard-codes the 
/etc/resolv.conf path and parses the file on its own, to obtain the 
search path and the configured name servers.

Once we add an environment variable to change the path, that's going to 
add a lot of confusion because the system will have an inconsistent view 
on the data.  I do not have a good answer to that.

Thanks,
Florian
  
Carlos O'Donell Sept. 18, 2017, 3:27 p.m. UTC | #5
On 09/18/2017 09:12 AM, Florian Weimer wrote:
> My main concern at this point is that a lot of software hard-codes
> the /etc/resolv.conf path and parses the file on its own, to obtain
> the search path and the configured name servers.
> 
> Once we add an environment variable to change the path, that's going
> to add a lot of confusion because the system will have an
> inconsistent view on the data.  I do not have a good answer to that.

Restating my position from August 18th (up thread):

Making there only be 1 way to set the resolver configuration makes it
easier for application developers, and administrators to manage and
develop such systems.

The only remaining alternative is to have glibc become responsible for
maintaining the consistency between /etc/resolv.conf and the env var.
It would require hiding the difference to the application using one
or other complex implementations e.g. mount namespace, hijacked open,
etc. I don't see a good tradeoff between the value of the new feature
and the complexity of the implementation. Higher level frameworks
will likely already need mount namespaces for other reasons so it
makes sense to delegate the normal system configuration to those
frameworks.
  

Patch

diff --git a/resolv/resolv.h b/resolv/resolv.h
index e8c581ccd1..5e7a8143c3 100644
--- a/resolv/resolv.h
+++ b/resolv/resolv.h
@@ -91,7 +91,10 @@ 
  */
 
 #ifndef _PATH_RESCONF
-#define _PATH_RESCONF        "/etc/resolv.conf"
+#define _PATH_RESCONF        ({ \
+		char *path_resconf = getenv("PATH_RESCONF"); \
+		path_resconf ? path_resconf : "/etc/resolv.conf"; \
+		})
 #endif
 
 struct res_sym {