Modules to become dynamically loadable modules?

Hello unbound users!

I have been digging around existing modules for unbound. There are some quite nice, dnstap module for example. We package unbound for fedora and rhel, but do not build alternative modules like redis, ipset or dnscrypt.

Main reason for it is dependencies dragged into libunbound.so. Because our packaging would drag more unnecessary dependencies with each depending application, gnutls-dane for example. The more we enable during build, the more would get linked into libunbound. Which is quite nice library for general DNS resolution and I would recommend it for more complex resolution. But external module dependencies would make every application using it require more packages.

I know most people does not need those modules. And they are made as modules separate already, but not as loadable code. Of course problem is they often have non-trivial configuration parts.

But unbound already supports dynlibmod, which kind of prepares loading of external code. Could it be expanded a bit more to provide also configuration snippets and known loadable modules?

Our unbound-libs package now depends on libprotobuf-c.so.1, among others. Because we wanted dnstap. I think for general distributions, this approach does not scale well. Ideally I would have unbound-dnstap subpackage, which would only depend on protobuf-c. Another unbound-redis, unbound-ipset, etc. But basic daemon would not link to external libraries, only crypto libraries.

Is there specific reason, why loadable module cannot be dlopened only when cachedb module is specified? Similar with any interesting features, which are less common and have external library dependencies? dynlibmod seems capable of such thing, but would make modules configuration look weird. Especially when cachedb requires own section in configuration. dynlibmod does not seem to support additional configuration processed in module.

I expect those questions have already appeared. Were there any reasons why modules are not (yet?) separate loadable code, but linked into main library? Are there some blockers, why it should not be made such way?

Regards,
Petr

Hi Petr!

Two separate things, building the library and modules.

For your specific case, couldn't you build Unbound two times?
One with all the configured modules you want and install the daemon from that build?

The other configured with --with-libunbound-only and install a probably vanilla, no extra configured modules only library to be used by other programs?

As for the modules, the modularity is there for the developer and user to be able to easily try new/extra features without polluting the main logic of other features/functionality. This is how it started.
Then the Python module made it possible to have your own Python logic attached into Unbound. And the dynlibmod came after that as providing the same black box functionality without having to rely on Python.

The main reason for not having runtime loadable modules is that it was not designed for that in the first place. It could be done but I believe yours is the first request that at least I know of.
People could argue that this behaviour does not sound secure and they would rather have the functionality compiled in the code.
I was told that there was such an argument way back for NSD.
I mean for core modules; dynlibmod for other stuff is something that you need to explicitly configure/consent so that's on the user to decide.

As for configuration of dynamically loaded modules, it can already happen if desired during initialization of the module (i.e., read your own configuration from a source) but not as part of Unbound's config file.

Best regards,
-- Yorgos

Hi Yorgos,

we kind of would like to limit dependencies both of unbound-libs and unbound package. Ideally with having unbound-extras package with all additional plugins we can compile from existing sources. That would not create extra copy of unbound code, which would be mostly the same. Easy usage of loadable modules specified just by name is missing now IMO.

More bits below.

Hi Petr!

Two separate things, building the library and modules.

For your specific case, couldn't you build Unbound two times?
One with all the configured modules you want and install the daemon from that build?

The other configured with --with-libunbound-only and install a probably vanilla, no extra configured modules only library to be used by other programs?

Yes, that seems to be the only possiblity now. That would mean unbound itself would link statically to own unbound library with more features.

We have recently realized we may need DNS over TLS configured early in system installation process. We want to use unbound for that. But that would mean unbound might need to be already in initramdisk image used to boot installer kernel. Therefore also unboud itself should not have extra dependencies not used at that time. Not just unbound libraries.

At the same time, it is quite unlikely we would need dnstap feature in the installer. Similar with python module support, although we will need python anyway.

As for the modules, the modularity is there for the developer and user to be able to easily try new/extra features without polluting the main logic of other features/functionality. This is how it started.
Then the Python module made it possible to have your own Python logic attached into Unbound. And the dynlibmod came after that as providing the same black box functionality without having to rely on Python.

The main reason for not having runtime loadable modules is that it was not designed for that in the first place. It could be done but I believe yours is the first request that at least I know of.
People could argue that this behaviour does not sound secure and they would rather have the functionality compiled in the code.
I was told that there was such an argument way back for NSD.
I mean for core modules; dynlibmod for other stuff is something that you need to explicitly configure/consent so that's on the user to decide.

Yes, well it depends on how trusted is code allowed to execute on your machine, which is running unbound code. We think network may not be trusted, but we need to trust local code to some extent. We can for example use SELinux contexts to allow modules used from unbound, but not allow unbound library clients to use some others. But that limits only non-root users. Root user can typically avoid any protection. We can prevent unbound process to load plugins from wrong paths for example, if SELinux is in enforcing mode. Which is the default on Fedora or RHEL. Of course such plugin directory must be writable only by root (and package manager).

I thought about creating modified version of dynlibmod. It kind of does what I would need, but the usage of modules loaded that way is weird. I would like more plugin compiled as "/usr/lib64/unbound/libdnstap.so", where just adding dnstap into module-config: would locate in predefined /usr/lib64/unbound directory, if found there. Otherwise the configuration would look like exactly the same as now when built-in.

As for configuration of dynamically loaded modules, it can already happen if desired during initialization of the module (i.e., read your own configuration from a source) but not as part of Unbound's config file.

Best regards,
-- Yorgos

Yes, but I meant more avoiding multiple module-config: "dynlib dynlib iterator validator", if I use two modules loaded via dynlib. Then I need to have two modules.

dynlib:
dynlib-file: "/usr/lib64/unbound/libdnstap.so"

dynlib:
dynlib-file: "/usr/lib64/unbound/libipset.so"

Separate section from those would be dnstap: section, configuring the module details. It works, but it is kind of weird. Just by iterating directory defined at compile time it might detect list of available external plugins and enable them from module-config. Of course built-in modules would be preferred. I would just make unbound -V to list also runtime detected available modules, similar to current Linked modules.