"Fossies" - the Fresh Open Source Software Archive

Member "knot-2.9.2/src/knot/server/server.c" (12 Dec 2019, 24505 Bytes) of package /linux/misc/dns/knot-2.9.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "server.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.1_vs_2.9.2.

    1 /*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
    2 
    3     This program is free software: you can redistribute it and/or modify
    4     it under the terms of the GNU General Public License as published by
    5     the Free Software Foundation, either version 3 of the License, or
    6     (at your option) any later version.
    7 
    8     This program is distributed in the hope that it will be useful,
    9     but WITHOUT ANY WARRANTY; without even the implied warranty of
   10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11     GNU General Public License for more details.
   12 
   13     You should have received a copy of the GNU General Public License
   14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
   15  */
   16 
   17 #define __APPLE_USE_RFC_3542
   18 
   19 #include <stdlib.h>
   20 #include <assert.h>
   21 #include <netinet/tcp.h>
   22 
   23 #include "libknot/errcode.h"
   24 #include "libknot/yparser/ypschema.h"
   25 #include "knot/common/log.h"
   26 #include "knot/common/stats.h"
   27 #include "knot/conf/confio.h"
   28 #include "knot/conf/migration.h"
   29 #include "knot/conf/module.h"
   30 #include "knot/dnssec/kasp/kasp_db.h"
   31 #include "knot/journal/journal_basic.h"
   32 #include "knot/server/server.h"
   33 #include "knot/server/udp-handler.h"
   34 #include "knot/server/tcp-handler.h"
   35 #include "knot/zone/timers.h"
   36 #include "knot/zone/zonedb-load.h"
   37 #include "knot/worker/pool.h"
   38 #include "contrib/net.h"
   39 #include "contrib/sockaddr.h"
   40 #include "contrib/trim.h"
   41 
   42 /*! \brief Minimal send/receive buffer sizes. */
   43 enum {
   44     UDP_MIN_RCVSIZE = 4096,
   45     UDP_MIN_SNDSIZE = 4096,
   46     TCP_MIN_RCVSIZE = 4096,
   47     TCP_MIN_SNDSIZE = sizeof(uint16_t) + UINT16_MAX
   48 };
   49 
   50 /*! \brief Unbind interface and clear the structure. */
   51 static void server_deinit_iface(iface_t *iface)
   52 {
   53     assert(iface);
   54 
   55     /* Free UDP handler. */
   56     if (iface->fd_udp != NULL) {
   57         for (int i = 0; i < iface->fd_udp_count; i++) {
   58             if (iface->fd_udp[i] > -1) {
   59                 close(iface->fd_udp[i]);
   60             }
   61         }
   62         free(iface->fd_udp);
   63     }
   64 
   65     /* Free TCP handler. */
   66     if (iface->fd_tcp != NULL) {
   67         for (int i = 0; i < iface->fd_tcp_count; i++) {
   68             if (iface->fd_tcp[i] > -1) {
   69                 close(iface->fd_tcp[i]);
   70             }
   71         }
   72         free(iface->fd_tcp);
   73     }
   74 
   75     free(iface);
   76 }
   77 
   78 /*! \brief Deinit server interface list. */
   79 static void server_deinit_iface_list(list_t *ifaces)
   80 {
   81     if (ifaces != NULL) {
   82         iface_t *iface, *next;
   83         WALK_LIST_DELSAFE(iface, next, *ifaces) {
   84             server_deinit_iface(iface);
   85         }
   86         free(ifaces);
   87     }
   88 }
   89 
   90 /*! \brief Set lower bound for socket option. */
   91 static bool setsockopt_min(int sock, int option, int min)
   92 {
   93     int value = 0;
   94     socklen_t len = sizeof(value);
   95 
   96     if (getsockopt(sock, SOL_SOCKET, option, &value, &len) != 0) {
   97         return false;
   98     }
   99 
  100     assert(len == sizeof(value));
  101     if (value >= min) {
  102         return true;
  103     }
  104 
  105     return setsockopt(sock, SOL_SOCKET, option, &min, sizeof(min)) == 0;
  106 }
  107 
  108 /*!
  109  * \brief Enlarge send/receive buffers.
  110  */
  111 static bool enlarge_net_buffers(int sock, int min_recvsize, int min_sndsize)
  112 {
  113     return setsockopt_min(sock, SO_RCVBUF, min_recvsize) &&
  114            setsockopt_min(sock, SO_SNDBUF, min_sndsize);
  115 }
  116 
  117 /*!
  118  * \brief Enable source packet information retrieval.
  119  */
  120 static bool enable_pktinfo(int sock, int family)
  121 {
  122     int level = 0;
  123     int option = 0;
  124 
  125     switch (family) {
  126     case AF_INET:
  127         level = IPPROTO_IP;
  128 #if defined(IP_PKTINFO)
  129         option = IP_PKTINFO; /* Linux */
  130 #elif defined(IP_RECVDSTADDR)
  131         option = IP_RECVDSTADDR; /* BSD */
  132 #else
  133         return false;
  134 #endif
  135         break;
  136     case AF_INET6:
  137         level = IPPROTO_IPV6;
  138         option = IPV6_RECVPKTINFO;
  139         break;
  140     default:
  141         return false;
  142     }
  143 
  144     const int on = 1;
  145     return setsockopt(sock, level, option, &on, sizeof(on)) == 0;
  146 }
  147 
  148 /*!
  149  * Linux 3.15 has IP_PMTUDISC_OMIT which makes sockets
  150  * ignore PMTU information and send packets with DF=0.
  151  * Fragmentation is allowed if and only if the packet
  152  * size exceeds the outgoing interface MTU or the packet
  153  * encounters smaller MTU link in network.
  154  * This mitigates DNS fragmentation attacks by preventing
  155  * forged PMTU information.
  156  * FreeBSD already has same semantics without setting
  157  * the option.
  158  */
  159 static int disable_pmtudisc(int sock, int family)
  160 {
  161 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT)
  162     if (family == AF_INET) {
  163         int action_omit = IP_PMTUDISC_OMIT;
  164         if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &action_omit,
  165             sizeof(action_omit)) != 0) {
  166             return knot_map_errno();
  167         }
  168     }
  169 #endif
  170     return KNOT_EOK;
  171 }
  172 
  173 /*!
  174  * \brief Enable TCP Fast Open.
  175  */
  176 static int enable_fastopen(int sock, int backlog)
  177 {
  178 #if defined(TCP_FASTOPEN)
  179 #if __APPLE__
  180     if (backlog > 0) {
  181         backlog = 1; // just on-off switch on macOS
  182     }
  183 #endif
  184     if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &backlog, sizeof(backlog)) != 0) {
  185         return knot_map_errno();
  186     }
  187 #endif
  188     return KNOT_EOK;
  189 }
  190 
  191 /*!
  192  * \brief Create and initialize new interface.
  193  *
  194  * Both TCP and UDP sockets will be created for the interface.
  195  *
  196  * \param addr              Socket address.
  197  * \param udp_thread_count  Number of created UDP workers.
  198  * \param tcp_thread_count  Number of created TCP workers.
  199  * \param tcp_reuseport     Indication if reuseport on TCP is enabled.
  200  *
  201  * \retval Pointer to a new initialized inteface.
  202  * \retval NULL if error.
  203  */
  204 static iface_t *server_init_iface(struct sockaddr_storage *addr,
  205                                   int udp_thread_count, int tcp_thread_count,
  206                                   bool tcp_reuseport)
  207 {
  208     iface_t *new_if = calloc(1, sizeof(*new_if));
  209     if (new_if == NULL) {
  210         log_error("failed to initialize interface");
  211         return NULL;
  212     }
  213     memcpy(&new_if->addr, addr, sizeof(*addr));
  214 
  215     /* Convert to string address format. */
  216     char addr_str[SOCKADDR_STRLEN] = { 0 };
  217     sockaddr_tostr(addr_str, sizeof(addr_str), addr);
  218 
  219     int udp_socket_count = 1;
  220     int udp_bind_flags = 0;
  221     int tcp_socket_count = 1;
  222     int tcp_bind_flags = 0;
  223 
  224 #ifdef ENABLE_REUSEPORT
  225     udp_socket_count = udp_thread_count;
  226     udp_bind_flags |= NET_BIND_MULTIPLE;
  227 
  228     if (tcp_reuseport) {
  229         tcp_socket_count = tcp_thread_count;
  230         tcp_bind_flags |= NET_BIND_MULTIPLE;
  231     }
  232 #endif
  233 
  234     new_if->fd_udp = malloc(udp_socket_count * sizeof(int));
  235     new_if->fd_tcp = malloc(tcp_socket_count * sizeof(int));
  236     if (new_if->fd_udp == NULL || new_if->fd_tcp == NULL) {
  237         log_error("failed to initialize interface");
  238         server_deinit_iface(new_if);
  239         return NULL;
  240     }
  241 
  242     bool warn_bind = true;
  243     bool warn_bufsize = true;
  244     bool warn_pktinfo = true;
  245     bool warn_flag_misc = true;
  246 
  247     /* Create bound UDP sockets. */
  248     for (int i = 0; i < udp_socket_count; i++) {
  249         int sock = net_bound_socket(SOCK_DGRAM, addr, udp_bind_flags);
  250         if (sock == KNOT_EADDRNOTAVAIL) {
  251             udp_bind_flags |= NET_BIND_NONLOCAL;
  252             sock = net_bound_socket(SOCK_DGRAM, addr, udp_bind_flags);
  253             if (sock >= 0 && warn_bind) {
  254                 log_warning("address %s UDP bound, but required nonlocal bind", addr_str);
  255                 warn_bind = false;
  256             }
  257         }
  258 
  259         if (sock < 0) {
  260             log_error("cannot bind address %s UDP (%s)", addr_str,
  261                       knot_strerror(sock));
  262             server_deinit_iface(new_if);
  263             return NULL;
  264         }
  265 
  266         if (!enlarge_net_buffers(sock, UDP_MIN_RCVSIZE, UDP_MIN_SNDSIZE) &&
  267             warn_bufsize) {
  268             log_warning("failed to set network buffer sizes for UDP");
  269             warn_bufsize = false;
  270         }
  271 
  272         if (sockaddr_is_any(addr) && !enable_pktinfo(sock, addr->ss_family) &&
  273             warn_pktinfo) {
  274             log_warning("failed to enable received packet information retrieval");
  275             warn_pktinfo = false;
  276         }
  277 
  278         int ret = disable_pmtudisc(sock, addr->ss_family);
  279         if (ret != KNOT_EOK && warn_flag_misc) {
  280             log_warning("failed to disable Path MTU discovery for IPv4/UDP (%s)",
  281                         knot_strerror(ret));
  282             warn_flag_misc = false;
  283         }
  284 
  285         new_if->fd_udp[new_if->fd_udp_count] = sock;
  286         new_if->fd_udp_count += 1;
  287     }
  288 
  289     warn_bind = true;
  290     warn_bufsize = true;
  291     warn_flag_misc = true;
  292 
  293     /* Create bound TCP sockets. */
  294     for (int i = 0; i < tcp_socket_count; i++) {
  295         int sock = net_bound_socket(SOCK_STREAM, addr, tcp_bind_flags);
  296         if (sock == KNOT_EADDRNOTAVAIL) {
  297             tcp_bind_flags |= NET_BIND_NONLOCAL;
  298             sock = net_bound_socket(SOCK_STREAM, addr, tcp_bind_flags);
  299             if (sock >= 0 && warn_bind) {
  300                 log_warning("address %s TCP bound, but required nonlocal bind", addr_str);
  301                 warn_bind = false;
  302             }
  303         }
  304 
  305         if (sock < 0) {
  306             log_error("cannot bind address %s TCP (%s)", addr_str,
  307                       knot_strerror(sock));
  308             server_deinit_iface(new_if);
  309             return NULL;
  310         }
  311 
  312         if (!enlarge_net_buffers(sock, TCP_MIN_RCVSIZE, TCP_MIN_SNDSIZE) &&
  313             warn_bufsize) {
  314             log_warning("failed to set network buffer sizes for TCP");
  315             warn_bufsize = false;
  316         }
  317 
  318         new_if->fd_tcp[new_if->fd_tcp_count] = sock;
  319         new_if->fd_tcp_count += 1;
  320 
  321         /* Listen for incoming connections. */
  322         int ret = listen(sock, TCP_BACKLOG_SIZE);
  323         if (ret < 0) {
  324             log_error("failed to listen on TCP interface %s", addr_str);
  325             server_deinit_iface(new_if);
  326             return NULL;
  327         }
  328 
  329         /* TCP Fast Open. */
  330         ret = enable_fastopen(sock, TCP_BACKLOG_SIZE);
  331         if (ret < 0 && warn_flag_misc) {
  332             log_warning("failed to enable TCP Fast Open on %s (%s)",
  333                         addr_str, knot_strerror(ret));
  334             warn_flag_misc = false;
  335         }
  336     }
  337 
  338     return new_if;
  339 }
  340 
  341 /*! \brief Initialize bound sockets according to configuration. */
  342 static int configure_sockets(conf_t *conf, server_t *s)
  343 {
  344     if (s->state & ServerRunning) {
  345         return KNOT_EOK;
  346     }
  347 
  348     /* Prepare helper lists. */
  349     list_t *newlist = malloc(sizeof(list_t));
  350     if (newlist == NULL) {
  351         return KNOT_ENOMEM;
  352     }
  353     init_list(newlist);
  354 
  355 #ifdef ENABLE_REUSEPORT
  356     /* Log info if reuseport is used and for what protocols. */
  357     log_info("using reuseport for UDP%s", conf->cache.srv_tcp_reuseport ? " and TCP" : "");
  358 #endif
  359 
  360     /* Update bound interfaces. */
  361     conf_val_t listen_val = conf_get(conf, C_SRV, C_LISTEN);
  362     conf_val_t rundir_val = conf_get(conf, C_SRV, C_RUNDIR);
  363     char *rundir = conf_abs_path(&rundir_val, NULL);
  364     while (listen_val.code == KNOT_EOK) {
  365         /* Log interface binding. */
  366         struct sockaddr_storage addr = conf_addr(&listen_val, rundir);
  367         char addr_str[SOCKADDR_STRLEN] = { 0 };
  368         sockaddr_tostr(addr_str, sizeof(addr_str), &addr);
  369         log_info("binding to interface %s", addr_str);
  370 
  371         /* Create new interface. */
  372         unsigned size_udp = s->handlers[IO_UDP].handler.unit->size;
  373         unsigned size_tcp = s->handlers[IO_TCP].handler.unit->size;
  374         bool tcp_reuseport = conf->cache.srv_tcp_reuseport;
  375         iface_t *new_if = server_init_iface(&addr, size_udp, size_tcp, tcp_reuseport);
  376         if (new_if != NULL) {
  377             add_tail(newlist, &new_if->n);
  378         }
  379 
  380         conf_val_next(&listen_val);
  381     }
  382     free(rundir);
  383 
  384     /* Publish new list. */
  385     s->ifaces = newlist;
  386 
  387     /* Set the ID's (thread_id) of both the TCP and UDP threads. */
  388     unsigned thread_count = 0;
  389     for (unsigned proto = IO_UDP; proto <= IO_TCP; ++proto) {
  390         dt_unit_t *tu = s->handlers[proto].handler.unit;
  391         for (unsigned i = 0; i < tu->size; ++i) {
  392             s->handlers[proto].handler.thread_id[i] = thread_count++;
  393         }
  394     }
  395 
  396     return KNOT_EOK;
  397 }
  398 
  399 int server_init(server_t *server, int bg_workers)
  400 {
  401     if (server == NULL) {
  402         return KNOT_EINVAL;
  403     }
  404 
  405     /* Clear the structure. */
  406     memset(server, 0, sizeof(server_t));
  407 
  408     /* Initialize event scheduler. */
  409     if (evsched_init(&server->sched, server) != KNOT_EOK) {
  410         return KNOT_ENOMEM;
  411     }
  412 
  413     server->workers = worker_pool_create(bg_workers);
  414     if (server->workers == NULL) {
  415         evsched_deinit(&server->sched);
  416         return KNOT_ENOMEM;
  417     }
  418 
  419     char *journal_dir = conf_db(conf(), C_JOURNAL_DB);
  420     conf_val_t journal_size = conf_db_param(conf(), C_JOURNAL_DB_MAX_SIZE, C_MAX_JOURNAL_DB_SIZE);
  421     conf_val_t journal_mode = conf_db_param(conf(), C_JOURNAL_DB_MODE, C_JOURNAL_DB_MODE);
  422     knot_lmdb_init(&server->journaldb, journal_dir, conf_int(&journal_size), journal_env_flags(conf_opt(&journal_mode)), NULL);
  423     free(journal_dir);
  424 
  425     char *kasp_dir = conf_db(conf(), C_KASP_DB);
  426     conf_val_t kasp_size = conf_db_param(conf(), C_KASP_DB_MAX_SIZE, C_MAX_KASP_DB_SIZE);
  427     knot_lmdb_init(&server->kaspdb, kasp_dir, conf_int(&kasp_size), 0, "keys_db");
  428     free(kasp_dir);
  429 
  430     char *timer_dir = conf_db(conf(), C_TIMER_DB);
  431     conf_val_t timer_size = conf_db_param(conf(), C_TIMER_DB_MAX_SIZE, C_MAX_TIMER_DB_SIZE);
  432     knot_lmdb_init(&server->timerdb, timer_dir, conf_int(&timer_size), 0, NULL);
  433     free(timer_dir);
  434 
  435     return KNOT_EOK;
  436 }
  437 
  438 void server_deinit(server_t *server)
  439 {
  440     if (server == NULL) {
  441         return;
  442     }
  443 
  444     /* Save zone timers. */
  445     if (server->zone_db != NULL) {
  446         log_info("updating persistent timer DB");
  447         int ret = zone_timers_write_all(&server->timerdb, server->zone_db);
  448         if (ret != KNOT_EOK) {
  449             log_warning("failed to update persistent timer DB (%s)",
  450                     knot_strerror(ret));
  451         }
  452     }
  453 
  454     /* Free remaining interfaces. */
  455     server_deinit_iface_list(server->ifaces);
  456 
  457     /* Free threads and event handlers. */
  458     worker_pool_destroy(server->workers);
  459 
  460     /* Free zone database. */
  461     knot_zonedb_deep_free(&server->zone_db, true);
  462 
  463     /* Free remaining events. */
  464     evsched_deinit(&server->sched);
  465 
  466     /* Close persistent timers DB. */
  467     knot_lmdb_deinit(&server->timerdb);
  468 
  469     /* Close kasp_db. */
  470     knot_lmdb_deinit(&server->kaspdb);
  471 
  472     /* Close journal database if open. */
  473     knot_lmdb_deinit(&server->journaldb);
  474 }
  475 
  476 static int server_init_handler(server_t *server, int index, int thread_count,
  477                                runnable_t runnable, runnable_t destructor)
  478 {
  479     /* Initialize */
  480     iohandler_t *h = &server->handlers[index].handler;
  481     memset(h, 0, sizeof(iohandler_t));
  482     h->server = server;
  483     h->unit = dt_create(thread_count, runnable, destructor, h);
  484     if (h->unit == NULL) {
  485         return KNOT_ENOMEM;
  486     }
  487 
  488     h->thread_state = calloc(thread_count, sizeof(unsigned));
  489     if (h->thread_state == NULL) {
  490         dt_delete(&h->unit);
  491         return KNOT_ENOMEM;
  492     }
  493 
  494     h->thread_id = calloc(thread_count, sizeof(unsigned));
  495     if (h->thread_id == NULL) {
  496         free(h->thread_state);
  497         dt_delete(&h->unit);
  498         return KNOT_ENOMEM;
  499     }
  500 
  501     return KNOT_EOK;
  502 }
  503 
  504 static void server_free_handler(iohandler_t *h)
  505 {
  506     if (h == NULL || h->server == NULL) {
  507         return;
  508     }
  509 
  510     /* Wait for threads to finish */
  511     if (h->unit) {
  512         dt_stop(h->unit);
  513         dt_join(h->unit);
  514     }
  515 
  516     /* Destroy worker context. */
  517     dt_delete(&h->unit);
  518     free(h->thread_state);
  519     free(h->thread_id);
  520 }
  521 
  522 int server_start(server_t *server, bool async)
  523 {
  524     if (server == NULL) {
  525         return KNOT_EINVAL;
  526     }
  527 
  528     /* Start workers. */
  529     worker_pool_start(server->workers);
  530 
  531     /* Wait for enqueued events if not asynchronous. */
  532     if (!async) {
  533         worker_pool_wait(server->workers);
  534     }
  535 
  536     /* Start evsched handler. */
  537     evsched_start(&server->sched);
  538 
  539     /* Start I/O handlers. */
  540     server->state |= ServerRunning;
  541     for (int proto = IO_UDP; proto <= IO_TCP; ++proto) {
  542         if (server->handlers[proto].size > 0) {
  543             int ret = dt_start(server->handlers[proto].handler.unit);
  544             if (ret != KNOT_EOK) {
  545                 return ret;
  546             }
  547         }
  548     }
  549 
  550     return KNOT_EOK;
  551 }
  552 
  553 void server_wait(server_t *server)
  554 {
  555     if (server == NULL) {
  556         return;
  557     }
  558 
  559     evsched_join(&server->sched);
  560     worker_pool_join(server->workers);
  561 
  562     for (int proto = IO_UDP; proto <= IO_TCP; ++proto) {
  563         if (server->handlers[proto].size > 0) {
  564             server_free_handler(&server->handlers[proto].handler);
  565         }
  566     }
  567 }
  568 
  569 static int reload_conf(conf_t *new_conf)
  570 {
  571     yp_schema_purge_dynamic(new_conf->schema);
  572 
  573     /* Re-load common modules. */
  574     int ret = conf_mod_load_common(new_conf);
  575     if (ret != KNOT_EOK) {
  576         return ret;
  577     }
  578 
  579     /* Re-import zonefile if specified. */
  580     const char *filename = conf()->filename;
  581     if (filename != NULL) {
  582         log_info("reloading configuration file '%s'", filename);
  583 
  584         /* Import the configuration file. */
  585         ret = conf_import(new_conf, filename, true, false);
  586         if (ret != KNOT_EOK) {
  587             log_error("failed to load configuration file (%s)",
  588                       knot_strerror(ret));
  589             return ret;
  590         }
  591     } else {
  592         log_info("reloading configuration database '%s'",
  593                  knot_db_lmdb_get_path(new_conf->db));
  594 
  595         /* Re-load extra modules. */
  596         for (conf_iter_t iter = conf_iter(new_conf, C_MODULE);
  597              iter.code == KNOT_EOK; conf_iter_next(new_conf, &iter)) {
  598             conf_val_t id = conf_iter_id(new_conf, &iter);
  599             conf_val_t file = conf_id_get(new_conf, C_MODULE, C_FILE, &id);
  600             ret = conf_mod_load_extra(new_conf, conf_str(&id), conf_str(&file), false);
  601             if (ret != KNOT_EOK) {
  602                 conf_iter_finish(new_conf, &iter);
  603                 return ret;
  604             }
  605         }
  606     }
  607 
  608     conf_mod_load_purge(new_conf, false);
  609 
  610     // Migrate from old schema.
  611     ret = conf_migrate(new_conf);
  612     if (ret != KNOT_EOK) {
  613         log_error("failed to migrate configuration (%s)", knot_strerror(ret));
  614     }
  615 
  616     /* Refresh hostname. */
  617     conf_refresh_hostname(new_conf);
  618 
  619     return KNOT_EOK;
  620 }
  621 
  622 /*! \brief Check if parameter listen has been changed since knotd started. */
  623 static bool listen_changed(conf_t *conf, server_t *server)
  624 {
  625     assert(server->ifaces);
  626 
  627     conf_val_t listen_val = conf_get(conf, C_SRV, C_LISTEN);
  628     size_t new_count = conf_val_count(&listen_val);
  629     size_t old_count = list_size(server->ifaces);
  630     if (new_count != old_count) {
  631         return true;
  632     }
  633 
  634     conf_val_t rundir_val = conf_get(conf, C_SRV, C_RUNDIR);
  635     char *rundir = conf_abs_path(&rundir_val, NULL);
  636     size_t matches = 0;
  637 
  638     /* Find matching interfaces. */
  639     while (listen_val.code == KNOT_EOK) {
  640         struct sockaddr_storage addr = conf_addr(&listen_val, rundir);
  641         bool found = false;
  642         iface_t *iface;
  643         WALK_LIST(iface, *server->ifaces) {
  644             if (sockaddr_cmp(&addr, &iface->addr) == 0) {
  645                 matches++;
  646                 found = true;
  647                 break;
  648             }
  649         }
  650 
  651         if (!found) {
  652             break;
  653         }
  654         conf_val_next(&listen_val);
  655     }
  656 
  657     free(rundir);
  658 
  659     return matches != old_count;
  660 }
  661 
  662 /*! \brief Log warnings if config change requires a restart. */
  663 static void warn_server_reconfigure(conf_t *conf, server_t *server)
  664 {
  665     const char *msg = "changes of %s require restart to take effect";
  666 
  667     static bool warn_tcp_reuseport = true;
  668     static bool warn_udp = true;
  669     static bool warn_tcp = true;
  670     static bool warn_bg = true;
  671     static bool warn_listen = true;
  672 
  673     if (warn_tcp_reuseport && conf->cache.srv_tcp_reuseport != conf_tcp_reuseport(conf)) {
  674         log_warning(msg, "tcp-reuseport");
  675         warn_tcp_reuseport = false;
  676     }
  677 
  678     if (warn_udp && server->handlers[IO_UDP].size != conf_udp_threads(conf)) {
  679         log_warning(msg, "udp-workers");
  680         warn_udp = false;
  681     }
  682 
  683     if (warn_tcp && server->handlers[IO_TCP].size != conf_tcp_threads(conf)) {
  684         log_warning(msg, "tcp-workers");
  685         warn_tcp = false;
  686     }
  687 
  688     if (warn_bg && conf->cache.srv_bg_threads != conf_bg_threads(conf)) {
  689         log_warning(msg, "background-workers");
  690         warn_bg = false;
  691     }
  692 
  693     if (warn_listen && listen_changed(conf, server)) {
  694         log_warning(msg, "listen");
  695         warn_listen = false;
  696     }
  697 }
  698 
  699 int server_reload(server_t *server)
  700 {
  701     if (server == NULL) {
  702         return KNOT_EINVAL;
  703     }
  704 
  705     /* Check for no edit mode. */
  706     if (conf()->io.txn != NULL) {
  707         log_warning("reload aborted due to active configuration transaction");
  708         return KNOT_TXN_EEXISTS;
  709     }
  710 
  711     conf_t *new_conf = NULL;
  712     int ret = conf_clone(&new_conf);
  713     if (ret != KNOT_EOK) {
  714         log_error("failed to initialize configuration (%s)",
  715                   knot_strerror(ret));
  716         return ret;
  717     }
  718 
  719     yp_flag_t flags = conf()->io.flags;
  720     bool full = !(flags & CONF_IO_FACTIVE);
  721     bool reuse_modules = !full && !(flags & CONF_IO_FRLD_MOD);
  722 
  723     /* Reload configuration and modules if full reload or a module change. */
  724     if (full || !reuse_modules) {
  725         ret = reload_conf(new_conf);
  726         if (ret != KNOT_EOK) {
  727             conf_free(new_conf);
  728             return ret;
  729         }
  730 
  731         conf_activate_modules(new_conf, NULL, new_conf->query_modules,
  732                               &new_conf->query_plan);
  733     }
  734 
  735     conf_update_flag_t upd_flags = CONF_UPD_FNOFREE;
  736     if (!full) {
  737         upd_flags |= CONF_UPD_FCONFIO;
  738     }
  739     if (reuse_modules) {
  740         upd_flags |= CONF_UPD_FMODULES;
  741     }
  742 
  743     /* Update to the new config. */
  744     conf_t *old_conf = conf_update(new_conf, upd_flags);
  745 
  746     /* Reload each component if full reload or a specific one if required. */
  747     if (full || (flags & CONF_IO_FRLD_LOG)) {
  748         log_reconfigure(conf());
  749     }
  750     if (full || (flags & CONF_IO_FRLD_SRV)) {
  751         server_reconfigure(conf(), server);
  752         warn_server_reconfigure(conf(), server);
  753         stats_reconfigure(conf(), server);
  754     }
  755     if (full || (flags & (CONF_IO_FRLD_ZONES | CONF_IO_FRLD_ZONE))) {
  756         server_update_zones(conf(), server);
  757     }
  758 
  759     /* Free old config needed for module unload in zone reload. */
  760     conf_free(old_conf);
  761 
  762     if (full) {
  763         log_info("configuration reloaded");
  764     } else {
  765         // Reset confio reload context.
  766         conf()->io.flags = YP_FNONE;
  767         if (conf()->io.zones != NULL) {
  768             trie_clear(conf()->io.zones);
  769         }
  770     }
  771 
  772     return KNOT_EOK;
  773 }
  774 
  775 void server_stop(server_t *server)
  776 {
  777     log_info("stopping server");
  778 
  779     /* Stop scheduler. */
  780     evsched_stop(&server->sched);
  781     /* Interrupt background workers. */
  782     worker_pool_stop(server->workers);
  783 
  784     /* Clear 'running' flag. */
  785     server->state &= ~ServerRunning;
  786 }
  787 
  788 static int set_handler(server_t *server, int index, unsigned size, runnable_t run)
  789 {
  790     /* Initialize I/O handlers. */
  791     int ret = server_init_handler(server, index, size, run, NULL);
  792     if (ret != KNOT_EOK) {
  793         return ret;
  794     }
  795 
  796     server->handlers[index].size = size;
  797 
  798     return KNOT_EOK;
  799 }
  800 
  801 /*! \brief Reconfigure UDP and TCP query processing threads. */
  802 static int configure_threads(conf_t *conf, server_t *server)
  803 {
  804     int ret = set_handler(server, IO_UDP, conf->cache.srv_udp_threads, udp_master);
  805     if (ret != KNOT_EOK) {
  806         return ret;
  807     }
  808 
  809     return set_handler(server, IO_TCP, conf->cache.srv_tcp_threads, tcp_master);
  810 }
  811 
  812 static int reconfigure_journal_db(conf_t *conf, server_t *server)
  813 {
  814     char *journal_dir = conf_db(conf, C_JOURNAL_DB);
  815     conf_val_t journal_size = conf_db_param(conf, C_JOURNAL_DB_MAX_SIZE, C_MAX_JOURNAL_DB_SIZE);
  816     conf_val_t journal_mode = conf_db_param(conf, C_JOURNAL_DB_MODE, C_JOURNAL_DB_MODE);
  817     int ret = knot_lmdb_reinit(&server->journaldb, journal_dir, conf_int(&journal_size),
  818                                journal_env_flags(conf_opt(&journal_mode)));
  819     if (ret != KNOT_EOK) {
  820         log_warning("ignored reconfiguration of journal DB (%s)", knot_strerror(ret));
  821     }
  822     free(journal_dir);
  823 
  824     return KNOT_EOK; // not "ret"
  825 }
  826 
  827 static int reconfigure_kasp_db(conf_t *conf, server_t *server)
  828 {
  829     char *kasp_dir = conf_db(conf, C_KASP_DB);
  830     conf_val_t kasp_size = conf_db_param(conf, C_KASP_DB_MAX_SIZE, C_MAX_KASP_DB_SIZE);
  831     int ret = knot_lmdb_reinit(&server->kaspdb, kasp_dir, conf_int(&kasp_size), 0);
  832     if (ret != KNOT_EOK) {
  833         log_warning("ignored reconfiguration of KASP DB (%s)", knot_strerror(ret));
  834     }
  835     free(kasp_dir);
  836 
  837     return KNOT_EOK; // not "ret"
  838 }
  839 
  840 static int reconfigure_timer_db(conf_t *conf, server_t *server)
  841 {
  842     char *timer_dir = conf_db(conf, C_TIMER_DB);
  843     conf_val_t timer_size = conf_db_param(conf, C_TIMER_DB_MAX_SIZE, C_MAX_TIMER_DB_SIZE);
  844     int ret = knot_lmdb_reconfigure(&server->timerdb, timer_dir, conf_int(&timer_size), 0);
  845     free(timer_dir);
  846     return ret;
  847 }
  848 
  849 void server_reconfigure(conf_t *conf, server_t *server)
  850 {
  851     if (conf == NULL || server == NULL) {
  852         return;
  853     }
  854 
  855     int ret;
  856 
  857     /* First reconfiguration. */
  858     if (!(server->state & ServerRunning)) {
  859         log_info("Knot DNS %s starting", PACKAGE_VERSION);
  860 
  861         if (conf->filename != NULL) {
  862             log_info("loaded configuration file '%s'",
  863                      conf->filename);
  864         } else {
  865             log_info("loaded configuration database '%s'",
  866                      knot_db_lmdb_get_path(conf->db));
  867         }
  868 
  869         /* Configure server threads. */
  870         if ((ret = configure_threads(conf, server)) != KNOT_EOK) {
  871             log_error("failed to configure server threads (%s)",
  872                       knot_strerror(ret));
  873         }
  874 
  875         /* Configure sockets. */
  876         if ((ret = configure_sockets(conf, server)) != KNOT_EOK) {
  877             log_error("failed to configure server sockets (%s)",
  878                       knot_strerror(ret));
  879         }
  880     }
  881 
  882     /* Reconfigure journal DB. */
  883     if ((ret = reconfigure_journal_db(conf, server)) != KNOT_EOK) {
  884         log_error("failed to reconfigure journal DB (%s)",
  885                   knot_strerror(ret));
  886     }
  887 
  888     /* Reconfigure KASP DB. */
  889     if ((ret = reconfigure_kasp_db(conf, server)) != KNOT_EOK) {
  890         log_error("failed to reconfigure KASP DB (%s)",
  891                   knot_strerror(ret));
  892     }
  893 
  894     /* Reconfiure Timer DB. */
  895     if ((ret = reconfigure_timer_db(conf, server)) != KNOT_EOK) {
  896         log_error("failed to reconfigure Timer DB (%s)",
  897                   knot_strerror(ret));
  898     }
  899 }
  900 
  901 void server_update_zones(conf_t *conf, server_t *server)
  902 {
  903     if (conf == NULL || server == NULL) {
  904         return;
  905     }
  906 
  907     /* Prevent emitting of new zone events. */
  908     if (server->zone_db) {
  909         knot_zonedb_foreach(server->zone_db, zone_events_freeze);
  910     }
  911 
  912     /* Suspend adding events to worker pool queue, wait for queued events. */
  913     evsched_pause(&server->sched);
  914     worker_pool_wait(server->workers);
  915 
  916     /* Reload zone database and free old zones. */
  917     zonedb_reload(conf, server);
  918 
  919     /* Trim extra heap. */
  920     mem_trim();
  921 
  922     /* Resume processing events on new zones. */
  923     evsched_resume(&server->sched);
  924     if (server->zone_db) {
  925         knot_zonedb_foreach(server->zone_db, zone_events_start);
  926     }
  927 }