1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /** @defgroup
36  *  @ingroup
37  *  @brief
38  *
39  *
40  *
41  * @{
42  *
43  *----------------------------------------------------------------------------*/
44 
45 #include "server-config.h"
46 
47 #define DYNAMIC_MODULE_HANDLER_C 1
48 
49 #include <dlfcn.h>
50 
51 #include <dnscore/logger.h>
52 #include <dnscore/parsing.h>
53 #include <dnscore/mutex.h>
54 #include <dnscore/ptr_set.h>
55 
56 #include "confs.h"
57 
58 struct dynamic_module_interface_chain;
59 struct dynamic_module_dnskey_interface_chain;
60 
61 struct dynamic_module_interface_chain *g_dynamic_module_interface_chain = NULL;
62 struct dynamic_module_dnskey_interface_chain *g_dynamic_module_dnskey_interface_chain = NULL;
63 struct dynamic_module_statistics_interface_chain *g_dynamic_module_statistics_interface_chain = NULL;
64 
65 #include "dynamic-module-handler.h"
66 #include "server.h"
67 
68 extern logger_handle *g_server_logger;
69 #define MODULE_MSG_HANDLE g_server_logger
70 
71 #define YDYNMOD_TAG 0x444f4d4e594459
72 #define YDYNMODA_TAG 0x41444f4d4e594459
73 #define YDYNMODI_TAG 0x49444f4d4e594459
74 #define YDYNMODK_TAG 0x4b444f4d4e594459
75 #define YDYNMODS_TAG 0x53444f4d4e594459
76 
77 logger_handle *g_module_logger = LOGGER_HANDLE_SINK;
78 #define CALLER_NAME "yadifad"
79 
80 struct dynamic_module
81 {
82     void *so;
83     dynamic_module_interface_init *entry_point;
84     char *path;
85     struct dynamic_module_settings_args args;
86     int rc;
87 };
88 
89 struct dynamic_module_interface_chain
90 {
91     struct dynamic_module_interface_chain *next;
92     struct dynamic_module *module;
93     struct dynamic_module_interface itf;
94 };
95 
96 struct dynamic_module_dnskey_interface_chain
97 {
98     struct dynamic_module_dnskey_interface_chain *next;
99     struct dynamic_module *module;
100     struct dynamic_module_dnskey_interface itf;
101 };
102 
103 
104 struct dynamic_module_statistics_interface_chain
105 {
106     struct dynamic_module_statistics_interface_chain *next;
107     struct dynamic_module *module;
108     struct dynamic_module_statistics_interface itf;
109 };
110 
111 static ptr_set dynamic_module_set = PTR_SET_ASCIIZ_EMPTY;
112 static mutex_t dynamic_module_mtx = MUTEX_INITIALIZER;
113 
114 /**
115  * Trivial.
116  */
117 
118 ya_result
dynamic_module_handler_init()119 dynamic_module_handler_init()
120 {
121     return SUCCESS;
122 }
123 
124 /**
125  * Trivial.
126  */
127 
128 ya_result
dynamic_module_handler_finalize()129 dynamic_module_handler_finalize()
130 {
131     return SUCCESS;
132 }
133 
134 /**
135  * Loads a module given its full path name (with luck relative may work too ... so yes: full path)
136  * Don't forget to take into account the choot.
137  *
138  * Modules should only be loaded AFTER the last fork.
139  */
140 
141 ya_result
dynamic_module_handler_load(int argc,const char ** argv)142 dynamic_module_handler_load(int argc, const char **argv)
143 {
144     if(argc <= 0)
145     {
146         return INVALID_ARGUMENT_ERROR;
147     }
148 
149     const char *shared_object_path = argv[0];
150 
151     log_debug("module: checking module '%s'", shared_object_path);
152 
153     ptr_node *node;
154     mutex_lock(&dynamic_module_mtx);
155     node = ptr_set_find(&dynamic_module_set, shared_object_path);
156 
157     if(node != NULL)
158     {
159         // already known
160 
161         mutex_unlock(&dynamic_module_mtx);
162         return SUCCESS;
163     }
164 
165     void *so = dlopen(shared_object_path, RTLD_NOLOAD);
166 
167     if(so == NULL)
168     {
169         so = dlopen(shared_object_path, RTLD_NOW/*|RTDL_LOCAL*/);
170 
171         if(so != NULL)
172         {
173             log_info("module: '%s': loaded", shared_object_path);
174 
175             // loaded
176 
177             // try to find the entry point
178 
179             void *f = dlsym(so, "module_interface_init");
180 
181             if(f == NULL)
182             {
183                 static const char suffix[] = "_interface_init";
184                 char module_interface_init_name[48];
185 
186                 // get the last '/'
187                 const char *start = parse_skip_until_chars(shared_object_path, "/", 1);
188                 // get the first '.'
189                 const char *stop = parse_skip_until_chars(stop, ".", 1);
190 
191                 if(stop == start)
192                 {
193                     stop = start + strlen(start);
194                 }
195 
196                 size_t len = stop - start;
197 
198                 if(len <= sizeof(module_interface_init_name) - sizeof(suffix))
199                 {
200                     memcpy(module_interface_init_name, start, len);
201                     memcpy(&module_interface_init_name[len], suffix, sizeof(suffix));
202 
203                     f = dlsym(so, module_interface_init_name);
204                 }
205             }
206 
207             if(f == NULL)
208             {
209                 mutex_unlock(&dynamic_module_mtx);
210 
211                 log_err("module: '%s': failed to find the entry point", shared_object_path);
212                 dlclose(so);
213                 return INVALID_STATE_ERROR;
214             }
215 
216             log_debug("module: '%s': got the entry point", shared_object_path);
217 
218             struct dynamic_module *module;
219             MALLOC_OBJECT_OR_DIE(module, struct dynamic_module, YDYNMOD_TAG);
220             MALLOC_OBJECT_ARRAY_OR_DIE(module->args.argv, char*, argc, YDYNMODA_TAG);
221             module->so = so;
222             module->entry_point = (dynamic_module_interface_init*)f;
223             module->path = strdup(shared_object_path);
224             module->rc = 0;
225 
226             struct dynamic_module_settings_args *args = &module->args;
227             args->sizeof_struct = sizeof(*args);
228             args->argc = argc;
229             memcpy(args->argv, argv, argc * sizeof(char*));
230             args->data_path = g_config->data_path;
231 
232             union dynamic_module_interfaces itfu;
233 
234             // DYNAMIC_MODULE_INTERFACE_ID
235             {
236                 itfu.interface.sizeof_struct = sizeof(itfu.interface);
237 
238                 if(ISOK(module->entry_point(DYNAMIC_MODULE_INTERFACE_ID, &itfu)))
239                 {
240                     // interface is supported
241                     log_debug("module: '%s': dynamic_module_interface is supported", shared_object_path);
242 
243                     if(itfu.interface.on_startup == NULL)
244                     {
245                         itfu.interface.on_startup = dynamic_module_startup_callback_nop;
246                     }
247 
248                     if(itfu.interface.on_settings_updated == NULL)
249                     {
250                         itfu.interface.on_settings_updated = dynamic_module_settings_callback_nop;
251                     }
252 
253                     if(itfu.interface.on_shutdown == NULL)
254                     {
255                         itfu.interface.on_shutdown = dynamic_module_shutdown_callback_nop;
256                     }
257 
258                     struct dynamic_module_interface_chain *ic;
259                     MALLOC_OBJECT_OR_DIE(ic, struct dynamic_module_interface_chain, YDYNMODI_TAG);
260                     ic->next = g_dynamic_module_interface_chain;
261                     ic->module = module;
262                     ++module->rc;
263                     memcpy(&ic->itf, &itfu.interface, sizeof(itfu.interface));
264                     g_dynamic_module_interface_chain = ic;
265                 }
266                 else
267                 {
268                     log_debug("module: '%s': dynamic_module_interface is not supported", shared_object_path);
269                 }
270             }
271 
272             // DYNAMIC_MODULE_DNSKEY_INTERFACE_ID
273             {
274                 itfu.dnskey_interface.sizeof_struct = sizeof(itfu.dnskey_interface);
275 
276                 if(ISOK(module->entry_point(DYNAMIC_MODULE_DNSKEY_INTERFACE_ID, &itfu)))
277                 {
278                     // interface is supported
279                     log_debug("module: '%s': dynamic_module_dnskey_interface is supported", shared_object_path);
280 
281                     if(itfu.dnskey_interface.on_dnskey_created == NULL)
282                     {
283                         itfu.dnskey_interface.on_dnskey_created = dynamic_module_on_dnskey_callback_nop;
284                     }
285 
286                     if(itfu.dnskey_interface.on_dnskey_publish == NULL)
287                     {
288                         itfu.dnskey_interface.on_dnskey_publish = dynamic_module_on_dnskey_callback_nop;
289                     }
290 
291                     if(itfu.dnskey_interface.on_dnskey_activate == NULL)
292                     {
293                         itfu.dnskey_interface.on_dnskey_activate = dynamic_module_on_dnskey_callback_nop;
294                     }
295 
296                     if(itfu.dnskey_interface.on_dnskey_revoke == NULL)
297                     {
298                         itfu.dnskey_interface.on_dnskey_revoke = dynamic_module_on_dnskey_callback_nop;
299                     }
300 
301                     if(itfu.dnskey_interface.on_dnskey_inactive == NULL)
302                     {
303                         itfu.dnskey_interface.on_dnskey_inactive = dynamic_module_on_dnskey_callback_nop;
304                     }
305 
306                     if(itfu.dnskey_interface.on_dnskey_delete == NULL)
307                     {
308                         itfu.dnskey_interface.on_dnskey_delete = dynamic_module_on_dnskey_callback_nop;
309                     }
310 
311                     struct dynamic_module_dnskey_interface_chain *ic;
312                     MALLOC_OBJECT_OR_DIE(ic, struct dynamic_module_dnskey_interface_chain, YDYNMODK_TAG);
313                     ic->next = g_dynamic_module_dnskey_interface_chain;
314                     ic->module = module;
315                     ++module->rc;
316                     memcpy(&ic->itf, &itfu.dnskey_interface, sizeof(itfu.dnskey_interface));
317                     g_dynamic_module_dnskey_interface_chain = ic;
318                 }
319                 else
320                 {
321                     log_debug("module: '%s': dynamic_module_dnskey_interface is not supported", shared_object_path);
322                 }
323             }
324 
325             // DYNAMIC_MODULE_STATISTICS_ID
326             {
327                 itfu.statistics_interface.sizeof_struct = sizeof(itfu.statistics_interface);
328 
329                 if(ISOK(module->entry_point(DYNAMIC_MODULE_STATISTICS_ID, &itfu)))
330                 {
331                     // interface is supported
332                     log_debug("module: '%s': dynamic_module_statistics_interface is supported", shared_object_path);
333 
334                     if(itfu.statistics_interface.on_statistics_update == NULL)
335                     {
336                         itfu.statistics_interface.on_statistics_update = dynamic_module_statistics_callback_nop;
337                     }
338 
339                     struct dynamic_module_statistics_interface_chain *ic;
340                     MALLOC_OBJECT_OR_DIE(ic, struct dynamic_module_statistics_interface_chain, YDYNMODS_TAG);
341                     ic->next = g_dynamic_module_statistics_interface_chain;
342                     ic->module = module;
343                     ++module->rc;
344                     memcpy(&ic->itf, &itfu.statistics_interface, sizeof(itfu.statistics_interface));
345                     g_dynamic_module_statistics_interface_chain = ic;
346                 }
347                 else
348                 {
349                     log_debug("module: '%s': dynamic_module_statistics_interface is not supported", shared_object_path);
350                 }
351             }
352 
353             node = ptr_set_insert(&dynamic_module_set, module->path);
354             node->key = module->path;
355             node->value = module;
356 
357             mutex_unlock(&dynamic_module_mtx);
358 
359             return SUCCESS;
360         }
361         else
362         {
363             // failed to load
364 
365             ret = ERRNO_ERROR;
366 
367             mutex_unlock(&dynamic_module_mtx);
368 
369             log_err("module: '%s': failed to load: %s", shared_object_path, dlerror());
370 
371             return ret;
372         }
373     }
374     else
375     {
376         // already loaded, somehow
377 
378         ret = ERRNO_ERROR;
379 
380         mutex_unlock(&dynamic_module_mtx);
381 
382         log_err("module: '%s': already loaded (albeit not through this handler)", shared_object_path);
383 
384         return ret;
385     }
386 }
387 
388 ya_result
dynamic_module_handler_load_from_command(const char * command)389 dynamic_module_handler_load_from_command(const char *command)
390 {
391     //const char *command_limit = &command[strlen(command)];
392     int argc = 0;
393     char *argv[128];
394     char tmp[PATH_MAX];
395 
396     s32 n;
397 
398     for(;;)
399     {
400         if(argc == sizeof(argv) / sizeof(char*))
401         {
402             n = -1; // too many parameters
403             break;
404         }
405 
406         n = parse_next_token(tmp, sizeof(tmp), command, " \t");
407 
408         if(n <= 0)
409         {
410             break;
411         }
412 
413         command += n;
414 
415         command = parse_skip_spaces(command);
416 
417         argv[argc++] = strdup(tmp);
418     }
419 
420     ya_result ret;
421 
422     if(n >= 0)
423     {
424         ret = dynamic_module_handler_load(argc, (const char**)argv);
425     }
426     else
427     {
428         ret = INVALID_ARGUMENT_ERROR; // too many parameters
429     }
430 
431     for(int i = 0; i < argc; ++i)
432     {
433         free(argv[i]);
434     }
435 
436     return ret;
437 }
438 
439 // interface
440 
441 void
dynamic_module_startup()442 dynamic_module_startup()
443 {
444     struct dynamic_module_interface_chain *dc = g_dynamic_module_interface_chain;
445     while(dc != NULL)
446     {
447         dc->itf.on_startup();
448         dc = dc->next;
449     }
450 }
451 
452 void
dynamic_module_settings()453 dynamic_module_settings()
454 {
455     struct dynamic_module_interface_chain *dc = g_dynamic_module_interface_chain;
456     if(dc != NULL)
457     {
458         do
459         {
460             dc->itf.on_settings_updated(&dc->module->args);
461             dc = dc->next;
462         }
463         while(dc != NULL);
464     }
465 }
466 
467 void
dynamic_module_shutdown()468 dynamic_module_shutdown()
469 {
470     struct dynamic_module_interface_chain *dc = g_dynamic_module_interface_chain;
471     while(dc != NULL)
472     {
473         dc->itf.on_shutdown();
474         dc = dc->next;
475     }
476 }
477 
478 // dnskey_interface
479 
480 ya_result
dynamic_module_on_dnskey_args_init(struct dynamic_module_on_dnskey_args * args,const dnssec_key * key,void * buffer,size_t buffer_size)481 dynamic_module_on_dnskey_args_init(struct dynamic_module_on_dnskey_args *args, const dnssec_key *key, void *buffer, size_t buffer_size)
482 {
483     args->sizeof_struct = sizeof(*args);
484     args->caller_name = CALLER_NAME;
485     args->origin = dnskey_get_domain(key);
486     args->rdata_size = key->vtbl->dnssec_key_rdatasize(key);
487 
488     if(args->rdata_size > buffer_size)
489     {
490         return BUFFER_WOULD_OVERFLOW;
491     }
492 
493     key->vtbl->dnssec_key_writerdata(key, buffer);
494     args->rdata = buffer;
495     args->epoch_created = dnskey_get_created_epoch(key);
496     args->epoch_publish = dnskey_get_publish_epoch(key);
497     args->epoch_activate = dnskey_get_activate_epoch(key);
498     args->epoch_revoke = 0;
499     args->epoch_inactive = dnskey_get_inactive_epoch(key);
500     args->epoch_delete = dnskey_get_delete_epoch(key);
501     args->flags = dnskey_get_flags(key);
502     args->tag = dnskey_get_tag_const(key);
503     args->algorithm = dnskey_get_algorithm(key);
504 
505     return SUCCESS;
506 }
507 
508 void
dynamic_module_on_dnskey_args_finalize(struct dynamic_module_on_dnskey_args * args)509 dynamic_module_on_dnskey_args_finalize(struct dynamic_module_on_dnskey_args *args)
510 {
511 #if DEBUG
512     ZEROMEMORY(args, sizeof(*args));
513 #else
514     (void)args;
515 #endif
516 }
517 
518 void
dynamic_module_on_dnskey_created(const dnssec_key * key)519 dynamic_module_on_dnskey_created(const dnssec_key *key)
520 {
521     struct dynamic_module_dnskey_interface_chain *dc = g_dynamic_module_dnskey_interface_chain;
522     if(dc != NULL)
523     {
524         struct dynamic_module_on_dnskey_args args;
525         char buffer[2048];
526 
527         if(ISOK(dynamic_module_on_dnskey_args_init(&args, key, buffer, sizeof(buffer))))
528         {
529             do
530             {
531                 dc->itf.on_dnskey_created(&args);
532                 dc = dc->next;
533             }
534             while(dc != NULL);
535 
536             dynamic_module_on_dnskey_args_finalize(&args);
537         }
538     }
539 }
540 
541 void
dynamic_module_on_dnskey_publish(const dnssec_key * key)542 dynamic_module_on_dnskey_publish(const dnssec_key *key)
543 {
544     struct dynamic_module_dnskey_interface_chain *dc = g_dynamic_module_dnskey_interface_chain;
545     if(dc != NULL)
546     {
547         struct dynamic_module_on_dnskey_args args;
548         char buffer[2048];
549 
550         dynamic_module_on_dnskey_args_init(&args, key, buffer, sizeof(buffer));
551 
552         do
553         {
554             dc->itf.on_dnskey_publish(&args);
555             dc = dc->next;
556         }
557         while(dc != NULL);
558 
559         dynamic_module_on_dnskey_args_finalize(&args);
560     }
561 }
562 
563 void
dynamic_module_on_dnskey_activate(const dnssec_key * key)564 dynamic_module_on_dnskey_activate(const dnssec_key *key)
565 {
566     struct dynamic_module_dnskey_interface_chain *dc = g_dynamic_module_dnskey_interface_chain;
567     if(dc != NULL)
568     {
569         struct dynamic_module_on_dnskey_args args;
570         char buffer[2048];
571 
572         dynamic_module_on_dnskey_args_init(&args, key, buffer, sizeof(buffer));
573 
574         do
575         {
576             dc->itf.on_dnskey_activate(&args);
577             dc = dc->next;
578         }
579         while(dc != NULL);
580 
581         dynamic_module_on_dnskey_args_finalize(&args);
582     }
583 }
584 
585 void
dynamic_module_on_dnskey_revoke(const dnssec_key * key)586 dynamic_module_on_dnskey_revoke(const dnssec_key *key)
587 {
588     struct dynamic_module_dnskey_interface_chain *dc = g_dynamic_module_dnskey_interface_chain;
589     if(dc != NULL)
590     {
591         struct dynamic_module_on_dnskey_args args;
592         char buffer[2048];
593 
594         dynamic_module_on_dnskey_args_init(&args, key, buffer, sizeof(buffer));
595 
596         do
597         {
598             dc->itf.on_dnskey_revoke(&args);
599             dc = dc->next;
600         }
601         while(dc != NULL);
602 
603         dynamic_module_on_dnskey_args_finalize(&args);
604     }
605 }
606 
607 void
dynamic_module_on_dnskey_inactive(const dnssec_key * key)608 dynamic_module_on_dnskey_inactive(const dnssec_key *key)
609 {
610     struct dynamic_module_dnskey_interface_chain *dc = g_dynamic_module_dnskey_interface_chain;
611     if(dc != NULL)
612     {
613         struct dynamic_module_on_dnskey_args args;
614         char buffer[2048];
615 
616         dynamic_module_on_dnskey_args_init(&args, key, buffer, sizeof(buffer));
617 
618         do
619         {
620             dc->itf.on_dnskey_inactive(&args);
621             dc = dc->next;
622         }
623         while(dc != NULL);
624 
625         dynamic_module_on_dnskey_args_finalize(&args);
626     }
627 }
628 
629 void
dynamic_module_on_dnskey_delete(const dnssec_key * key)630 dynamic_module_on_dnskey_delete(const dnssec_key *key)
631 {
632     struct dynamic_module_dnskey_interface_chain *dc = g_dynamic_module_dnskey_interface_chain;
633     if(dc != NULL)
634     {
635         struct dynamic_module_on_dnskey_args args;
636         char buffer[2048];
637 
638         dynamic_module_on_dnskey_args_init(&args, key, buffer, sizeof(buffer));
639 
640         do
641         {
642             dc->itf.on_dnskey_delete(&args);
643             dc = dc->next;
644         }
645         while(dc != NULL);
646 
647         dynamic_module_on_dnskey_args_finalize(&args);
648     }
649 }
650 
651 void
dynamic_module_on_statistics_update(server_statistics_t * st,u64 epoch)652 dynamic_module_on_statistics_update(server_statistics_t *st, u64 epoch)
653 {
654     struct dynamic_module_statistics_interface_chain *dc = g_dynamic_module_statistics_interface_chain;
655 
656     if(dc != NULL)
657     {
658         struct dynamic_module_statistics_args args;
659         struct dynamic_module_statistics_args_buffers args_buffers;
660 
661         args.sizeof_struct = sizeof(args);
662         args.epoch_us = epoch;
663 
664         args.input_loop_count = st->input_loop_count;
665         args.input_timeout_count = st->input_timeout_count;
666         args.loop_rate_counter = st->loop_rate_counter;
667         args.loop_rate_elapsed = st->loop_rate_elapsed;
668 
669         args.udp_input_count = st->udp_input_count;
670         args.udp_queries_count = st->udp_queries_count;
671         args.udp_notify_input_count = st->udp_notify_input_count;
672         args.udp_updates_count = st->udp_updates_count;
673         args.udp_dropped_count = st->udp_dropped_count;
674         args.udp_output_size_total = st->udp_output_size_total;
675         args.udp_undefined_count = st->udp_undefined_count;
676         args.udp_referrals_count = st->udp_referrals_count;
677 
678         args.tcp_input_count = st->tcp_input_count;
679         args.tcp_queries_count = st->tcp_queries_count;
680         args.tcp_notify_input_count = st->tcp_notify_input_count;
681         args.tcp_updates_count = st->tcp_updates_count;
682         args.tcp_dropped_count = st->tcp_dropped_count;
683         args.tcp_output_size_total = st->tcp_output_size_total;
684         args.tcp_undefined_count = st->tcp_undefined_count;
685         args.tcp_referrals_count = st->tcp_referrals_count;
686 
687         args.tcp_axfr_count = st->tcp_axfr_count;
688         args.tcp_ixfr_count = st->tcp_ixfr_count;
689         args.tcp_overflow_count = st->tcp_overflow_count;
690 
691         args.rrl_slip = st->rrl_slip;
692         args.rrl_drop = st->rrl_drop;
693 
694         args.udp_rcode_count = args_buffers.udp_rcode_buffer;
695         args.tcp_rcode_count = args_buffers.tcp_rcode_buffer;
696         args.udp_tsig_rcode_count = args_buffers.udp_tsig_rcode_buffer;
697         args.tcp_tsig_rcode_count = args_buffers.tcp_tsig_rcode_buffer;
698 
699         args.rcode_count_size = DYNAMIC_MODULE_STATISTICS_RCODE_COUNT;
700         args.tsig_rcode_count_size = DYNAMIC_MODULE_STATISTICS_TSIG_RCODE_COUNT;
701 
702         do
703         {
704             dc->itf.on_statistics_update(&args);
705             dc = dc->next;
706         }
707         while(dc != NULL);
708     }
709 }
710 
711 /**
712  * @}
713  */
714