New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add dynamic library support #93
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR, it looks good enough but there is some items to talk about and then some review comments. The review changes are small and I can also do them if you feel easier about that.
It is a good idea to settle on the function prototypes, pass all information. The memory allocation has to be clear. And the copyright lines, it would be nice to have them correct.
It is probably a good idea to pass the module_env in init() and deinit() and the outbound_entry for operate(). So all the data is available to the dynlib module.
you are passing qstate and qstate->data, both pointers that can be allocated by the module. But there is no set for them. There is a free(qstate->data) in the clear() , which is non overrideable.
I guess making the clear call also have an override function, that can then call free() or not. is best, because it could then allocate in the qstate->region, that is freed anyway. This means the function
prototypes do not need to pass the data pointer, really, but the qstate pointer, and then the example might allocate one and free it in clear().
Also the order of arguments could just be the same as the ones in the module_funcblock, right? Less confusion, perhaps.
the dynlibtest.dll should not be committed. Looks like the helloworld example compiled. No problem, just commit not necessary.
For lexer and yacc output, no problem we'll regenerate that. The Makefile produces them, by the way, and it was included to make the code repository useful for people in production that want an up to date
version of the software. I mean, easier to use it.
The dynlibmod/dynlibmod.h file has copyrights from the same people as did the pythonmod module, and not you. Is that true, or just a copy and paste? The BSD license is great to see, by the way, that is
nice, but the Copyright, if that is just a copy and paste thing then we should just remove it or some other name. Or it is actually from them, which is also great to have (just like the pythonmod contribution).
dynlibmod/dynlibmod.c:191, I would put brackets in there for the ?: operator.
:188 I would cast to struct dynlibmod_env* here.
:180 :194 the log_err, possibly that log should be at a different verbosity level. To stop spamming the logs if the module keeps failing?
:32 you mean log_err instead of log_info.
Other than that it looks good and ready to go! Thanks for the
great code!
Oh yes, documentation would need to be added, that is right.
example.conf, man page, testdata test to see if it works.
remove //
comments and replace with /* */
style.
:105 move to verbosity level debug, VERB_ALGO.
:107 declare variables at start of routine.
:113 in the log_err also print the filename that failed.
I will fix it up as much as possible, hopefully by the end of the day.
The interface here was all based on what the pythonmodule code does. I wasn't sure if these things were not passed along for any particular reason, but I guess not.
No set for them? Not quite sure what you mean by that. The
That is a good idea. I'll fix that. I guess this never came up as an issue in the pythonmodule since it's a garbage collected language.
I guess you mean that the order of arguments to the procedure in the dynamic library should be the same as the procedure that calls it? I agree, that would be nicer. Again, this is something that was simply copied over from the pythonmodule code, but I'll fix it.
Oh, not sure how that got in there. I'll remove it and force-push so that it doesn't enter your tree at all.
Didn't realise that the Makefile you create them, I guess since
Again just some lazy copy-pasting. The authors of the pythonmod module didn't have anything to do with this work. I personally tend to go for MIT when licensing things, but I'm fine with sticking to BSD, or any other open license you'd like.
Sure, which log level did you have in mind? Again this is just a copy from the Python version I'll polish it up and push an improved version. |
One question about the |
Sure, it is fine to expose the get_mem call to the module. |
For the license, for ease of management I guess we prefer the BSD license we are using already for this code repository. You can see some license words in doc/README, but most of the dependent packages are also BSD licensed, and that would make inclusion in other places (like FreeBSD) easier. So I would want to pick BSD out of the license options you present (even though libexpat we link with is MIT licensed, so that is not a bad option either). |
Dynamic library module is now only a thin wrapper that loads dynamic libraries and forwards all function calls directly to the loaded module. This meant adding get_mem and clear, and get_mem calls have been added in the expected places. Documentation has also been added to the example.conf and the unbound.conf manpage.
I more or less completely re-did the module now. It is a much thinner wrapper around the dynamic libraries, essentially just loading it, and then passing all further calls to the dynamic module. I also added Wrote some simple explanations in the I also fixed the copyright, but kept the BSD license. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, these changes look good!
Allows the use of multiple dynamic modules. Simply add more "dynlib" entries to the "modules-config" and the same amount of "dynlib-file" entries in the dynlib configuration block.
Added support for multiple modules to be loaded now. So what remains? Add some test in testdata and write a more explanatory example? |
Not quite sure how to implement a reasonable test case, any pointers on that? And for the example, is there anything in particular you had in mind? |
For the testcase, if you have an example c file , and the command to compile it, and then some dig statements that unbound (with that dynlib) should produce, or what log entries should appear. Then that should enable a testcase somehow, like from a shell script. (So you don't have to dive into our test setup). For the example, maybe print the query? Perform a malloc of per-query data so you can show the free of it in the clear() routine. If you want more than log statements and an example malloc, perhaps edit the answer, don't know. |
This adds the possibility to properly register inplace callbacks in the dynamic library module. It works by creating a wrapper procedure that is available to the dynamic library and will call the given callback through a whitelisted callback function. The dynamic library example has already been improved to include comments and some simple examples on allocating and deallocating memory and registering callbacks.
Improved the example a bit, and added the functionality of registering inplace callbacks similar to how it's done in the Python module. |
This adds the "dynlib: " prefix to all messages created by the `helloworld.c` dynamic library example. It also adds logging of queries that pass through `operate`.
Added the logging of queries (although with
That is of course with a |
The return code of the init procedure was just set to be 1 in the dynamic library loading module. This ha been rectified and it will now return whatever is returned from the loaded module.
Any input on how to add that as a test? It would be nice to have this resolved before it diverts too far from master. |
Still no input? As I said, it would be great to have this merged before it diverges too far.. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review looks good!
with dlclose and dlopen of the library again. Also for multiple modules. Fix memory leak by not closing dlopened content. Fix to allow one dynlibmod instance by unbound-checkconf.
- windows compile warnings removal for ip dscp option code.
Thanks for the feature and code fixups! Added fixups and a test so that should make it more neatly integrated into the unbound code base. |
* nlnet/master: (25 commits) - For PR NLnetLabs#93: unit test for dynlib module. - For PR NLnetLabs#93: windows compile warnings removal - windows compile warnings removal for ip dscp option code. - Release 1.10.1 is 1.10.0 with fixes, code repository continues, including those fixes, towards the next release. Configure has version 1.10.2 version number in it. - CVE-2020-12662 Unbound can be tricked into amplifying an incoming query into a large number of queries directed to a target. - CVE-2020-12663 Malformed answers from upstream name servers can be used to make Unbound unresponsive. - For PR NLnetLabs#93: fix link of other executables for dynlibmod dependency. - For PR NLnetLabs#93: man page spelling reference fix. - For PR NLnetLabs#93: checkconf allows python dynlib in module-config, for a couple cases. - For PR NLnetLabs#93: checkconf allow multiple dynlib in module-config, for a couple cases. - For PR NLnetLabs#93: dynlibmod can handle reloads and deinit and inits again, with dlclose and dlopen of the library again. Also for multiple modules. Fix memory leak by not closing dlopened content. Fix to allow one dynlibmod instance by unbound-checkconf. - For PR NLnetLabs#93: Fix warnings for dynlibmodule. - Fixed conflicts for PR NLnetLabs#93 and make configure, yacc, lex. - Cache ECS answers with longest scope of CNAME chain. - Explicitly use 'rrset-roundrobin: no' for test cases. - Fix tests for new rrset-roundrobin default. Changelog note for PR NLnetLabs#225 - Merge NLnetLabs#225 from akhait: KSK-2010 has been revoked. It removes the KSK-2010 from the default list in unbound-anchor, now that the revocation period is over. KSK-2017 is the only trust anchor in the shipped default now. KSK-2010 has been revoked - Change default value for 'rrset-roundrobin' to yes. - Remove unneeded was_mesh_reply check. Fix return code of init to mirror native modules Add "dynlib" prefix to example output, log queries ...
* 'master' of github.com:jedisct1/unbound: - For PR NLnetLabs#93: unit test for dynlib module. - For PR NLnetLabs#93: windows compile warnings removal - windows compile warnings removal for ip dscp option code. - Release 1.10.1 is 1.10.0 with fixes, code repository continues, including those fixes, towards the next release. Configure has version 1.10.2 version number in it. - CVE-2020-12662 Unbound can be tricked into amplifying an incoming query into a large number of queries directed to a target. - CVE-2020-12663 Malformed answers from upstream name servers can be used to make Unbound unresponsive. - For PR NLnetLabs#93: fix link of other executables for dynlibmod dependency. - For PR NLnetLabs#93: man page spelling reference fix. - For PR NLnetLabs#93: checkconf allows python dynlib in module-config, for a couple cases. - For PR NLnetLabs#93: checkconf allow multiple dynlib in module-config, for a couple cases. - For PR NLnetLabs#93: dynlibmod can handle reloads and deinit and inits again, with dlclose and dlopen of the library again. Also for multiple modules. Fix memory leak by not closing dlopened content. Fix to allow one dynlibmod instance by unbound-checkconf. - For PR NLnetLabs#93: Fix warnings for dynlibmodule. - Fixed conflicts for PR NLnetLabs#93 and make configure, yacc, lex. - Cache ECS answers with longest scope of CNAME chain. Fix return code of init to mirror native modules Add "dynlib" prefix to example output, log queries Add inplace callback to dynlibmod, improve example Cleanup some minor things in dynlibmod Add support for multiple dynamic modules Improve dynlib module and add documentation Add dynamic library support
Hmm, I tried migrating our tool to build with the latest version of Unbound (and as a test the first version of unbound that supported dynlibs) but I'm running into a weird issue. On Linux it works just fine, but on Windows I'm having some issues with linking. In my branch building a library and linking against
But when building against any of the released versions with dynlib support I get:
This obviously fails as it isn't able to use the internal functions from the dll. |
Did you enable |
No, I run |
I do not see how unbound-control.exe has anything to do with those lines. You could attempt to use libtool and libunbound.la; there are settings stored in libunbound.la that could be used by libtool to make a different commandline for you. libtool is what unbound's Makefile uses, Even though I think the commandline you cite is just fine. |
It seems like it is the building of |
This line from configure is causing it |
If I remove that libunbound.a and then re-run the make for unbound.exe with that out-implib for libfoo.a and then link helloworld.c example from dynlibmod, then it works and objdump -p shows unbound.exe as the first DLL. Is that what we need here? |
So I can compile cleanly for the dynlibmod example with But also with this line: |
Aah, so that was introduced with 4ccac69. Since I only needed |
I fixed it to only do those extra link lines for dynlibmodule for unbound.exe and that should fix the bug you had. I do not know if I can run that dll, but since yours works, we can use your version. The library is also called libunbound.a and this is confusing, should it maybe have a different name (and what name would you like?) so that is not the same as .libs/libunbound.a? |
That is a good point. I'm not exactly sure what the original |
The libunbound.a is an API implementation of libunbound/unbound.h that provides access to unbound like a library routine that you can call to look up names. This also has a python hook, pyunbound, where it can be used from a python script. |
Hmm, maybe call the new one |
Sure, if this gets installed to make people link dynamic modules with, something that also involves 'unbound' in the name as well. But I like the dynlibdefs part. |
I googled around a bit and there seems to be a weak naming convention on the form |
Okay can so that, it is a change in the EXTRALIBS in the Makefile and then the compile instructions for a dll -l:libunbound.dll.a . You want that for the compile instructions for dynamic modules, it may need explanation for people to understand what it is for, but if it does not conflict in the name that is good. |
Committed the fix that names it |
* nlnet/master: (33 commits) rpl tests for nsid example.conf.in entry for nsid - Fix declaration before statement and signed comparison warning in dns64. - Fix NLnetLabs#404: DNS query with small edns bufsize fail. Changelog entry for NLnetLabs#402. - Merge NLnetLabs#402 from fobser: Implement IPv4-Embedded addresses according to RFC6052. Implement IPv4-Embedded addresses according to RFC6052. - Fix for NLnetLabs#93: dynlibmodule import library is named libunbound.dll.a. - Fix for NLnetLabs#93: dynlibmodule link fix for Windows. Nicer changelog note for NLnetLabs#399 - Merge NLnetLabs#399 from xiangbao227: The lock of lruhash table should unlocked after markdel entry. Changelog note for NLnetLabs#399 - Merge NLnetLabs#399 from xiangbao227: The function rrset_cache_touch can touch an entry to the lru while markdelling the entry in lruhash_remove. I found that in function lruhash_remove, table was locked at first ,then lru_remove the entry , then unlock the table, and then markdel entry , but in function rrset_cache_touch , the entry will be touched to lru again before markdelling entry in function lruhash_remove. This is a bug! And man page documentation for them. - Fix so local zone types always_nodata and always_deny can be used from the config file. - Fix NLnetLabs#397: [Feature request] add new type always_null to local-zone similar to always_nxdomain. - Fix clang analysis warning. - Add comment documentation. - For NLnetLabs#391: more double casts in python start time calculation. - For NLnetLabs#391: fix indentation. - For NLnetLabs#391: use struct timeval* start_time for callback information. Changelog note for NLnetLabs#391 - Merge PR NLnetLabs#391 from fhriley: Add start_time to reply callbacks so modules can compute the response time. ...
This adds dynamic module (dll/so) support to Unbound. It works in a similar way to how the Python module loading does, simply configure with
--with-dynlibmodule
and you can now add a section in the configuration file like so:This will now be loaded into unbound and can access all procedures from it. A very simple example can be found in
dynlibmod/examples
that simply logs out messages when it gets called. It also has comments on how to build and cross compile this library for Linux and Windows.I have not included the configparser/-lexer files that gets generated by flex and bison with the commands found in makedist.sh as my locally installed versions are ahead of the ones used to build them in this repository. So the changes to these files aren't meaningful (by the way, why are these not automatically generated by autoconf/configure/make? Having auto-generated files in the repository isn't very nice).
NOTE: This code is not final. I would want to add similar support as the python module loading has to load multiple dynamic libraries, and I should add some more documentation and clean up the code a bit. This PR is meant to get feedback on the implementation as there is no reason to document this if it needs to change anyways.