lwresd.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2009, 2012-2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2000-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: lwresd.c,v 1.60 2009/09/02 23:48:01 tbox Exp $ */
00019 
00020 /*! \file
00021  * \brief
00022  * Main program for the Lightweight Resolver Daemon.
00023  *
00024  * To paraphrase the old saying about X11, "It's not a lightweight deamon
00025  * for resolvers, it's a deamon for lightweight resolvers".
00026  */
00027 
00028 #include <config.h>
00029 
00030 #include <stdlib.h>
00031 #include <string.h>
00032 
00033 #include <isc/list.h>
00034 #include <isc/magic.h>
00035 #include <isc/mem.h>
00036 #include <isc/once.h>
00037 #include <isc/print.h>
00038 #include <isc/socket.h>
00039 #include <isc/task.h>
00040 #include <isc/util.h>
00041 
00042 #include <isccfg/namedconf.h>
00043 
00044 #include <dns/log.h>
00045 #include <dns/result.h>
00046 #include <dns/view.h>
00047 
00048 #include <named/config.h>
00049 #include <named/globals.h>
00050 #include <named/log.h>
00051 #include <named/lwaddr.h>
00052 #include <named/lwresd.h>
00053 #include <named/lwdclient.h>
00054 #include <named/lwsearch.h>
00055 #include <named/server.h>
00056 
00057 #define LWRESD_MAGIC            ISC_MAGIC('L', 'W', 'R', 'D')
00058 #define VALID_LWRESD(l)         ISC_MAGIC_VALID(l, LWRESD_MAGIC)
00059 
00060 #define LWRESLISTENER_MAGIC     ISC_MAGIC('L', 'W', 'R', 'L')
00061 #define VALID_LWRESLISTENER(l)  ISC_MAGIC_VALID(l, LWRESLISTENER_MAGIC)
00062 
00063 #define LWRESD_NCLIENTS_MAX             32768   /*%< max clients per task */
00064 
00065 typedef ISC_LIST(ns_lwreslistener_t) ns_lwreslistenerlist_t;
00066 
00067 static ns_lwreslistenerlist_t listeners;
00068 static isc_mutex_t listeners_lock;
00069 static isc_once_t once = ISC_ONCE_INIT;
00070 
00071 
00072 static void
00073 initialize_mutex(void) {
00074         RUNTIME_CHECK(isc_mutex_init(&listeners_lock) == ISC_R_SUCCESS);
00075 }
00076 
00077 
00078 /*%
00079  * Wrappers around our memory management stuff, for the lwres functions.
00080  */
00081 void *
00082 ns__lwresd_memalloc(void *arg, size_t size) {
00083         return (isc_mem_get(arg, size));
00084 }
00085 
00086 void
00087 ns__lwresd_memfree(void *arg, void *mem, size_t size) {
00088         isc_mem_put(arg, mem, size);
00089 }
00090 
00091 
00092 #define CHECK(op)                                               \
00093         do { result = (op);                                     \
00094                 if (result != ISC_R_SUCCESS) goto cleanup;      \
00095         } while (0)
00096 
00097 static isc_result_t
00098 buffer_putstr(isc_buffer_t *b, const char *s) {
00099         unsigned int len = strlen(s);
00100         if (isc_buffer_availablelength(b) <= len)
00101                 return (ISC_R_NOSPACE);
00102         isc_buffer_putmem(b, (const unsigned char *)s, len);
00103         return (ISC_R_SUCCESS);
00104 }
00105 
00106 /*
00107  * Convert a resolv.conf file into a config structure.
00108  */
00109 isc_result_t
00110 ns_lwresd_parseeresolvconf(isc_mem_t *mctx, cfg_parser_t *pctx,
00111                            cfg_obj_t **configp)
00112 {
00113         char text[4096];
00114         char str[16];
00115         isc_buffer_t b;
00116         lwres_context_t *lwctx = NULL;
00117         lwres_conf_t *lwc = NULL;
00118         isc_sockaddr_t sa;
00119         isc_netaddr_t na;
00120         int i;
00121         isc_result_t result;
00122         lwres_result_t lwresult;
00123 
00124         lwctx = NULL;
00125         lwresult = lwres_context_create(&lwctx, mctx, ns__lwresd_memalloc,
00126                                         ns__lwresd_memfree,
00127                                         LWRES_CONTEXT_SERVERMODE);
00128         if (lwresult != LWRES_R_SUCCESS) {
00129                 result = ISC_R_NOMEMORY;
00130                 goto cleanup;
00131         }
00132 
00133         lwresult = lwres_conf_parse(lwctx, lwresd_g_resolvconffile);
00134         if (lwresult != LWRES_R_SUCCESS) {
00135                 result = DNS_R_SYNTAX;
00136                 goto cleanup;
00137         }
00138 
00139         lwc = lwres_conf_get(lwctx);
00140         INSIST(lwc != NULL);
00141 
00142         isc_buffer_init(&b, text, sizeof(text));
00143 
00144         CHECK(buffer_putstr(&b, "options {\n"));
00145 
00146         /*
00147          * Build the list of forwarders.
00148          */
00149         if (lwc->nsnext > 0) {
00150                 CHECK(buffer_putstr(&b, "\tforwarders {\n"));
00151 
00152                 for (i = 0; i < lwc->nsnext; i++) {
00153                         CHECK(lwaddr_sockaddr_fromlwresaddr(
00154                                                         &sa,
00155                                                         &lwc->nameservers[i],
00156                                                         ns_g_port));
00157                         isc_netaddr_fromsockaddr(&na, &sa);
00158                         CHECK(buffer_putstr(&b, "\t\t"));
00159                         CHECK(isc_netaddr_totext(&na, &b));
00160                         CHECK(buffer_putstr(&b, ";\n"));
00161                 }
00162                 CHECK(buffer_putstr(&b, "\t};\n"));
00163         }
00164 
00165         /*
00166          * Build the sortlist
00167          */
00168         if (lwc->sortlistnxt > 0) {
00169                 CHECK(buffer_putstr(&b, "\tsortlist {\n"));
00170                 CHECK(buffer_putstr(&b, "\t\t{\n"));
00171                 CHECK(buffer_putstr(&b, "\t\t\tany;\n"));
00172                 CHECK(buffer_putstr(&b, "\t\t\t{\n"));
00173                 for (i = 0; i < lwc->sortlistnxt; i++) {
00174                         lwres_addr_t *lwaddr = &lwc->sortlist[i].addr;
00175                         lwres_addr_t *lwmask = &lwc->sortlist[i].mask;
00176                         unsigned int mask;
00177 
00178                         CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwmask, 0));
00179                         isc_netaddr_fromsockaddr(&na, &sa);
00180                         result = isc_netaddr_masktoprefixlen(&na, &mask);
00181                         if (result != ISC_R_SUCCESS) {
00182                                 char addrtext[ISC_NETADDR_FORMATSIZE];
00183                                 isc_netaddr_format(&na, addrtext,
00184                                                    sizeof(addrtext));
00185                                 isc_log_write(ns_g_lctx,
00186                                               NS_LOGCATEGORY_GENERAL,
00187                                               NS_LOGMODULE_LWRESD,
00188                                               ISC_LOG_ERROR,
00189                                               "processing sortlist: '%s' is "
00190                                               "not a valid netmask",
00191                                               addrtext);
00192                                 goto cleanup;
00193                         }
00194 
00195                         CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwaddr, 0));
00196                         isc_netaddr_fromsockaddr(&na, &sa);
00197 
00198                         CHECK(buffer_putstr(&b, "\t\t\t\t"));
00199                         CHECK(isc_netaddr_totext(&na, &b));
00200                         snprintf(str, sizeof(str), "%u", mask);
00201                         CHECK(buffer_putstr(&b, "/"));
00202                         CHECK(buffer_putstr(&b, str));
00203                         CHECK(buffer_putstr(&b, ";\n"));
00204                 }
00205                 CHECK(buffer_putstr(&b, "\t\t\t};\n"));
00206                 CHECK(buffer_putstr(&b, "\t\t};\n"));
00207                 CHECK(buffer_putstr(&b, "\t};\n"));
00208         }
00209 
00210         CHECK(buffer_putstr(&b, "};\n\n"));
00211 
00212         CHECK(buffer_putstr(&b, "lwres {\n"));
00213 
00214         /*
00215          * Build the search path
00216          */
00217         if (lwc->searchnxt > 0) {
00218                 if (lwc->searchnxt > 0) {
00219                         CHECK(buffer_putstr(&b, "\tsearch {\n"));
00220                         for (i = 0; i < lwc->searchnxt; i++) {
00221                                 CHECK(buffer_putstr(&b, "\t\t\""));
00222                                 CHECK(buffer_putstr(&b, lwc->search[i]));
00223                                 CHECK(buffer_putstr(&b, "\";\n"));
00224                         }
00225                         CHECK(buffer_putstr(&b, "\t};\n"));
00226                 }
00227         }
00228 
00229         /*
00230          * Build the ndots line
00231          */
00232         if (lwc->ndots != 1) {
00233                 CHECK(buffer_putstr(&b, "\tndots "));
00234                 snprintf(str, sizeof(str), "%u", lwc->ndots);
00235                 CHECK(buffer_putstr(&b, str));
00236                 CHECK(buffer_putstr(&b, ";\n"));
00237         }
00238 
00239         /*
00240          * Build the listen-on line
00241          */
00242         if (lwc->lwnext > 0) {
00243                 CHECK(buffer_putstr(&b, "\tlisten-on {\n"));
00244 
00245                 for (i = 0; i < lwc->lwnext; i++) {
00246                         CHECK(lwaddr_sockaddr_fromlwresaddr(&sa,
00247                                                             &lwc->lwservers[i],
00248                                                             0));
00249                         isc_netaddr_fromsockaddr(&na, &sa);
00250                         CHECK(buffer_putstr(&b, "\t\t"));
00251                         CHECK(isc_netaddr_totext(&na, &b));
00252                         CHECK(buffer_putstr(&b, ";\n"));
00253                 }
00254                 CHECK(buffer_putstr(&b, "\t};\n"));
00255         }
00256 
00257         CHECK(buffer_putstr(&b, "};\n"));
00258 
00259 #if 0
00260         printf("%.*s\n",
00261                (int)isc_buffer_usedlength(&b),
00262                (char *)isc_buffer_base(&b));
00263 #endif
00264 
00265         lwres_conf_clear(lwctx);
00266         lwres_context_destroy(&lwctx);
00267 
00268         return (cfg_parse_buffer(pctx, &b, &cfg_type_namedconf, configp));
00269 
00270  cleanup:
00271 
00272         if (lwctx != NULL) {
00273                 lwres_conf_clear(lwctx);
00274                 lwres_context_destroy(&lwctx);
00275         }
00276 
00277         return (result);
00278 }
00279 
00280 
00281 /*
00282  * Handle lwresd manager objects
00283  */
00284 isc_result_t
00285 ns_lwdmanager_create(isc_mem_t *mctx, const cfg_obj_t *lwres,
00286                      ns_lwresd_t **lwresdp)
00287 {
00288         ns_lwresd_t *lwresd;
00289         const char *vname;
00290         dns_rdataclass_t vclass;
00291         const cfg_obj_t *obj, *viewobj, *searchobj;
00292         const cfg_listelt_t *element;
00293         isc_result_t result;
00294 
00295         INSIST(lwresdp != NULL && *lwresdp == NULL);
00296 
00297         lwresd = isc_mem_get(mctx, sizeof(ns_lwresd_t));
00298         if (lwresd == NULL)
00299                 return (ISC_R_NOMEMORY);
00300 
00301         lwresd->mctx = NULL;
00302         isc_mem_attach(mctx, &lwresd->mctx);
00303         lwresd->view = NULL;
00304         lwresd->search = NULL;
00305         lwresd->refs = 1;
00306 
00307         obj = NULL;
00308         (void)cfg_map_get(lwres, "ndots", &obj);
00309         if (obj != NULL)
00310                 lwresd->ndots = cfg_obj_asuint32(obj);
00311         else
00312                 lwresd->ndots = 1;
00313 
00314         RUNTIME_CHECK(isc_mutex_init(&lwresd->lock) == ISC_R_SUCCESS);
00315 
00316         lwresd->shutting_down = ISC_FALSE;
00317 
00318         viewobj = NULL;
00319         (void)cfg_map_get(lwres, "view", &viewobj);
00320         if (viewobj != NULL) {
00321                 vname = cfg_obj_asstring(cfg_tuple_get(viewobj, "name"));
00322                 obj = cfg_tuple_get(viewobj, "class");
00323                 result = ns_config_getclass(obj, dns_rdataclass_in, &vclass);
00324                 if (result != ISC_R_SUCCESS)
00325                         goto fail;
00326         } else {
00327                 vname = "_default";
00328                 vclass = dns_rdataclass_in;
00329         }
00330 
00331         result = dns_viewlist_find(&ns_g_server->viewlist, vname, vclass,
00332                                    &lwresd->view);
00333         if (result != ISC_R_SUCCESS) {
00334                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00335                               NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
00336                               "couldn't find view %s", vname);
00337                 goto fail;
00338         }
00339 
00340         searchobj = NULL;
00341         (void)cfg_map_get(lwres, "search", &searchobj);
00342         if (searchobj != NULL) {
00343                 lwresd->search = NULL;
00344                 result = ns_lwsearchlist_create(lwresd->mctx,
00345                                                 &lwresd->search);
00346                 if (result != ISC_R_SUCCESS) {
00347                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00348                                       NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
00349                                       "couldn't create searchlist");
00350                         goto fail;
00351                 }
00352                 for (element = cfg_list_first(searchobj);
00353                      element != NULL;
00354                      element = cfg_list_next(element))
00355                 {
00356                         const cfg_obj_t *search;
00357                         const char *searchstr;
00358                         isc_buffer_t namebuf;
00359                         dns_fixedname_t fname;
00360                         dns_name_t *name;
00361 
00362                         search = cfg_listelt_value(element);
00363                         searchstr = cfg_obj_asstring(search);
00364 
00365                         dns_fixedname_init(&fname);
00366                         name = dns_fixedname_name(&fname);
00367                         isc_buffer_constinit(&namebuf, searchstr,
00368                                         strlen(searchstr));
00369                         isc_buffer_add(&namebuf, strlen(searchstr));
00370                         result = dns_name_fromtext(name, &namebuf,
00371                                                    dns_rootname, 0, NULL);
00372                         if (result != ISC_R_SUCCESS) {
00373                                 isc_log_write(ns_g_lctx,
00374                                               NS_LOGCATEGORY_GENERAL,
00375                                               NS_LOGMODULE_LWRESD,
00376                                               ISC_LOG_WARNING,
00377                                               "invalid name %s in searchlist",
00378                                               searchstr);
00379                                 continue;
00380                         }
00381 
00382                         result = ns_lwsearchlist_append(lwresd->search, name);
00383                         if (result != ISC_R_SUCCESS) {
00384                                 isc_log_write(ns_g_lctx,
00385                                               NS_LOGCATEGORY_GENERAL,
00386                                               NS_LOGMODULE_LWRESD,
00387                                               ISC_LOG_WARNING,
00388                                               "couldn't update searchlist");
00389                                 goto fail;
00390                         }
00391                 }
00392         }
00393 
00394         obj = NULL;
00395         (void)cfg_map_get(lwres, "lwres-tasks", &obj);
00396         if (obj != NULL)
00397                 lwresd->ntasks = cfg_obj_asuint32(obj);
00398         else
00399                 lwresd->ntasks = ns_g_cpus;
00400 
00401         obj = NULL;
00402         (void)cfg_map_get(lwres, "lwres-clients", &obj);
00403         if (obj != NULL) {
00404                 lwresd->nclients = cfg_obj_asuint32(obj);
00405                 if (lwresd->nclients > LWRESD_NCLIENTS_MAX)
00406                         lwresd->nclients = LWRESD_NCLIENTS_MAX;
00407         } else if (ns_g_lwresdonly)
00408                 lwresd->nclients = 1024;
00409         else
00410                 lwresd->nclients = 256;
00411 
00412         lwresd->magic = LWRESD_MAGIC;
00413 
00414         *lwresdp = lwresd;
00415         return (ISC_R_SUCCESS);
00416 
00417  fail:
00418         if (lwresd->view != NULL)
00419                 dns_view_detach(&lwresd->view);
00420         if (lwresd->search != NULL)
00421                 ns_lwsearchlist_detach(&lwresd->search);
00422         if (lwresd->mctx != NULL)
00423                 isc_mem_detach(&lwresd->mctx);
00424         isc_mem_put(mctx, lwresd, sizeof(ns_lwresd_t));
00425         return (result);
00426 }
00427 
00428 void
00429 ns_lwdmanager_attach(ns_lwresd_t *source, ns_lwresd_t **targetp) {
00430         INSIST(VALID_LWRESD(source));
00431         INSIST(targetp != NULL && *targetp == NULL);
00432 
00433         LOCK(&source->lock);
00434         source->refs++;
00435         UNLOCK(&source->lock);
00436 
00437         *targetp = source;
00438 }
00439 
00440 void
00441 ns_lwdmanager_detach(ns_lwresd_t **lwresdp) {
00442         ns_lwresd_t *lwresd;
00443         isc_mem_t *mctx;
00444         isc_boolean_t done = ISC_FALSE;
00445 
00446         INSIST(lwresdp != NULL && *lwresdp != NULL);
00447         INSIST(VALID_LWRESD(*lwresdp));
00448 
00449         lwresd = *lwresdp;
00450         *lwresdp = NULL;
00451 
00452         LOCK(&lwresd->lock);
00453         INSIST(lwresd->refs > 0);
00454         lwresd->refs--;
00455         if (lwresd->refs == 0)
00456                 done = ISC_TRUE;
00457         UNLOCK(&lwresd->lock);
00458 
00459         if (!done)
00460                 return;
00461 
00462         dns_view_detach(&lwresd->view);
00463         if (lwresd->search != NULL)
00464                 ns_lwsearchlist_detach(&lwresd->search);
00465         mctx = lwresd->mctx;
00466         lwresd->magic = 0;
00467         isc_mem_put(mctx, lwresd, sizeof(*lwresd));
00468         isc_mem_detach(&mctx);
00469 }
00470 
00471 
00472 /*
00473  * Handle listener objects
00474  */
00475 void
00476 ns_lwreslistener_attach(ns_lwreslistener_t *source,
00477                         ns_lwreslistener_t **targetp)
00478 {
00479         INSIST(VALID_LWRESLISTENER(source));
00480         INSIST(targetp != NULL && *targetp == NULL);
00481 
00482         LOCK(&source->lock);
00483         source->refs++;
00484         UNLOCK(&source->lock);
00485 
00486         *targetp = source;
00487 }
00488 
00489 void
00490 ns_lwreslistener_detach(ns_lwreslistener_t **listenerp) {
00491         ns_lwreslistener_t *listener;
00492         isc_mem_t *mctx;
00493         isc_boolean_t done = ISC_FALSE;
00494 
00495         INSIST(listenerp != NULL && *listenerp != NULL);
00496         INSIST(VALID_LWRESLISTENER(*listenerp));
00497 
00498         listener = *listenerp;
00499 
00500         LOCK(&listener->lock);
00501         INSIST(listener->refs > 0);
00502         listener->refs--;
00503         if (listener->refs == 0)
00504                 done = ISC_TRUE;
00505         UNLOCK(&listener->lock);
00506 
00507         if (!done)
00508                 return;
00509 
00510         if (listener->manager != NULL)
00511                 ns_lwdmanager_detach(&listener->manager);
00512 
00513         if (listener->sock != NULL)
00514                 isc_socket_detach(&listener->sock);
00515 
00516         listener->magic = 0;
00517         mctx = listener->mctx;
00518         isc_mem_put(mctx, listener, sizeof(*listener));
00519         isc_mem_detach(&mctx);
00520         listenerp = NULL;
00521 }
00522 
00523 static isc_result_t
00524 listener_create(isc_mem_t *mctx, ns_lwresd_t *lwresd,
00525                 ns_lwreslistener_t **listenerp)
00526 {
00527         ns_lwreslistener_t *listener;
00528         isc_result_t result;
00529 
00530         REQUIRE(listenerp != NULL && *listenerp == NULL);
00531 
00532         listener = isc_mem_get(mctx, sizeof(ns_lwreslistener_t));
00533         if (listener == NULL)
00534                 return (ISC_R_NOMEMORY);
00535 
00536         result = isc_mutex_init(&listener->lock);
00537         if (result != ISC_R_SUCCESS) {
00538                 isc_mem_put(mctx, listener, sizeof(ns_lwreslistener_t));
00539                 return (result);
00540         }
00541 
00542         listener->magic = LWRESLISTENER_MAGIC;
00543         listener->refs = 1;
00544 
00545         listener->sock = NULL;
00546 
00547         listener->manager = NULL;
00548         ns_lwdmanager_attach(lwresd, &listener->manager);
00549 
00550         listener->mctx = NULL;
00551         isc_mem_attach(mctx, &listener->mctx);
00552 
00553         ISC_LINK_INIT(listener, link);
00554         ISC_LIST_INIT(listener->cmgrs);
00555 
00556         *listenerp = listener;
00557         return (ISC_R_SUCCESS);
00558 }
00559 
00560 static isc_result_t
00561 listener_bind(ns_lwreslistener_t *listener, isc_sockaddr_t *address) {
00562         isc_socket_t *sock = NULL;
00563         isc_result_t result = ISC_R_SUCCESS;
00564         int pf;
00565 
00566         pf = isc_sockaddr_pf(address);
00567         if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
00568             (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
00569                 return (ISC_R_FAMILYNOSUPPORT);
00570 
00571         listener->address = *address;
00572 
00573         if (isc_sockaddr_getport(&listener->address) == 0) {
00574                 in_port_t port;
00575                 port = lwresd_g_listenport;
00576                 if (port == 0)
00577                         port = LWRES_UDP_PORT;
00578                 isc_sockaddr_setport(&listener->address, port);
00579         }
00580 
00581         sock = NULL;
00582         result = isc_socket_create(ns_g_socketmgr, pf,
00583                                    isc_sockettype_udp, &sock);
00584         if (result != ISC_R_SUCCESS) {
00585                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00586                               NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
00587                               "failed to create lwres socket: %s",
00588                               isc_result_totext(result));
00589                 return (result);
00590         }
00591 
00592         result = isc_socket_bind(sock, &listener->address,
00593                                  ISC_SOCKET_REUSEADDRESS);
00594         if (result != ISC_R_SUCCESS) {
00595                 char socktext[ISC_SOCKADDR_FORMATSIZE];
00596                 isc_sockaddr_format(&listener->address, socktext,
00597                                     sizeof(socktext));
00598                 isc_socket_detach(&sock);
00599                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00600                               NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
00601                               "failed to add lwres socket: %s: %s",
00602                               socktext, isc_result_totext(result));
00603                 return (result);
00604         }
00605         listener->sock = sock;
00606         return (ISC_R_SUCCESS);
00607 }
00608 
00609 static void
00610 listener_copysock(ns_lwreslistener_t *oldlistener,
00611                   ns_lwreslistener_t *newlistener)
00612 {
00613         newlistener->address = oldlistener->address;
00614         isc_socket_attach(oldlistener->sock, &newlistener->sock);
00615 }
00616 
00617 static isc_result_t
00618 listener_startclients(ns_lwreslistener_t *listener) {
00619         ns_lwdclientmgr_t *cm;
00620         unsigned int i;
00621         isc_result_t result = ISC_R_SUCCESS;
00622 
00623         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00624                       NS_LOGMODULE_LWRESD, ISC_LOG_DEBUG(6),
00625                       "listener_startclients: creating %d "
00626                       "managers with %d clients each",
00627                       listener->manager->ntasks, listener->manager->nclients);
00628 
00629         /*
00630          * Create the client managers.
00631          */
00632         for (i = 0; i < listener->manager->ntasks; i++) {
00633                 result = ns_lwdclientmgr_create(listener,
00634                                                 listener->manager->nclients,
00635                                                 ns_g_taskmgr);
00636                 if (result != ISC_R_SUCCESS)
00637                         break;
00638         }
00639 
00640         /*
00641          * Ensure that we have created at least one.
00642          */
00643         if (ISC_LIST_EMPTY(listener->cmgrs))
00644                 return (result);
00645 
00646         /*
00647          * Walk the list of clients and start each one up.
00648          */
00649         LOCK(&listener->lock);
00650         cm = ISC_LIST_HEAD(listener->cmgrs);
00651         while (cm != NULL) {
00652                 result = ns_lwdclient_startrecv(cm);
00653                 if (result != ISC_R_SUCCESS)
00654                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00655                                       NS_LOGMODULE_LWRESD, ISC_LOG_ERROR,
00656                                       "could not start lwres "
00657                                       "client handler: %s",
00658                                       isc_result_totext(result));
00659                 cm = ISC_LIST_NEXT(cm, link);
00660         }
00661         UNLOCK(&listener->lock);
00662 
00663         return (ISC_R_SUCCESS);
00664 }
00665 
00666 static void
00667 listener_shutdown(ns_lwreslistener_t *listener) {
00668         ns_lwdclientmgr_t *cm;
00669 
00670         cm = ISC_LIST_HEAD(listener->cmgrs);
00671         while (cm != NULL) {
00672                 isc_task_shutdown(cm->task);
00673                 cm = ISC_LIST_NEXT(cm, link);
00674         }
00675 }
00676 
00677 static isc_result_t
00678 find_listener(isc_sockaddr_t *address, ns_lwreslistener_t **listenerp) {
00679         ns_lwreslistener_t *listener;
00680 
00681         INSIST(listenerp != NULL && *listenerp == NULL);
00682 
00683         for (listener = ISC_LIST_HEAD(listeners);
00684              listener != NULL;
00685              listener = ISC_LIST_NEXT(listener, link))
00686         {
00687                 if (!isc_sockaddr_equal(address, &listener->address))
00688                         continue;
00689                 *listenerp = listener;
00690                 return (ISC_R_SUCCESS);
00691         }
00692         return (ISC_R_NOTFOUND);
00693 }
00694 
00695 void
00696 ns_lwreslistener_unlinkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm)
00697 {
00698         REQUIRE(VALID_LWRESLISTENER(listener));
00699 
00700         LOCK(&listener->lock);
00701         ISC_LIST_UNLINK(listener->cmgrs, cm, link);
00702         UNLOCK(&listener->lock);
00703 }
00704 
00705 void
00706 ns_lwreslistener_linkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm) {
00707         REQUIRE(VALID_LWRESLISTENER(listener));
00708 
00709         /*
00710          * This does no locking, since it's called early enough that locking
00711          * isn't needed.
00712          */
00713         ISC_LIST_APPEND(listener->cmgrs, cm, link);
00714 }
00715 
00716 static isc_result_t
00717 configure_listener(isc_sockaddr_t *address, ns_lwresd_t *lwresd,
00718                    isc_mem_t *mctx, ns_lwreslistenerlist_t *newlisteners)
00719 {
00720         ns_lwreslistener_t *listener, *oldlistener = NULL;
00721         char socktext[ISC_SOCKADDR_FORMATSIZE];
00722         isc_result_t result;
00723 
00724         (void)find_listener(address, &oldlistener);
00725         listener = NULL;
00726         result = listener_create(mctx, lwresd, &listener);
00727         if (result != ISC_R_SUCCESS) {
00728                 isc_sockaddr_format(address, socktext, sizeof(socktext));
00729                 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
00730                               NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
00731                               "lwres failed to configure %s: %s",
00732                               socktext, isc_result_totext(result));
00733                 return (result);
00734         }
00735 
00736         /*
00737          * If there's already a listener, don't rebind the socket.
00738          */
00739         if (oldlistener == NULL) {
00740                 result = listener_bind(listener, address);
00741                 if (result != ISC_R_SUCCESS) {
00742                         ns_lwreslistener_detach(&listener);
00743                         return (ISC_R_SUCCESS);
00744                 }
00745         } else
00746                 listener_copysock(oldlistener, listener);
00747 
00748         result = listener_startclients(listener);
00749         if (result != ISC_R_SUCCESS) {
00750                 isc_sockaddr_format(address, socktext, sizeof(socktext));
00751                 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
00752                               NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
00753                               "lwres: failed to start %s: %s", socktext,
00754                               isc_result_totext(result));
00755                 ns_lwreslistener_detach(&listener);
00756                 return (ISC_R_SUCCESS);
00757         }
00758 
00759         if (oldlistener != NULL) {
00760                 /*
00761                  * Remove the old listener from the old list and shut it down.
00762                  */
00763                 ISC_LIST_UNLINK(listeners, oldlistener, link);
00764                 listener_shutdown(oldlistener);
00765                 ns_lwreslistener_detach(&oldlistener);
00766         } else {
00767                 isc_sockaddr_format(address, socktext, sizeof(socktext));
00768                 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
00769                               NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE,
00770                               "lwres listening on %s", socktext);
00771         }
00772 
00773         ISC_LIST_APPEND(*newlisteners, listener, link);
00774         return (result);
00775 }
00776 
00777 isc_result_t
00778 ns_lwresd_configure(isc_mem_t *mctx, const cfg_obj_t *config) {
00779         const cfg_obj_t *lwreslist = NULL;
00780         const cfg_obj_t *lwres = NULL;
00781         const cfg_obj_t *listenerslist = NULL;
00782         const cfg_listelt_t *element = NULL;
00783         ns_lwreslistener_t *listener;
00784         ns_lwreslistenerlist_t newlisteners;
00785         isc_result_t result;
00786         char socktext[ISC_SOCKADDR_FORMATSIZE];
00787         isc_sockaddr_t *addrs = NULL;
00788         ns_lwresd_t *lwresd = NULL;
00789         isc_uint32_t count = 0;
00790 
00791         REQUIRE(mctx != NULL);
00792         REQUIRE(config != NULL);
00793 
00794         RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
00795 
00796         ISC_LIST_INIT(newlisteners);
00797 
00798         result = cfg_map_get(config, "lwres", &lwreslist);
00799         if (result != ISC_R_SUCCESS)
00800                 return (ISC_R_SUCCESS);
00801 
00802         LOCK(&listeners_lock);
00803         /*
00804          * Run through the new lwres address list, noting sockets that
00805          * are already being listened on and moving them to the new list.
00806          *
00807          * Identifying duplicates addr/port combinations is left to either
00808          * the underlying config code, or to the bind attempt getting an
00809          * address-in-use error.
00810          */
00811         for (element = cfg_list_first(lwreslist);
00812              element != NULL;
00813              element = cfg_list_next(element))
00814         {
00815                 in_port_t port;
00816 
00817                 lwres = cfg_listelt_value(element);
00818                 CHECK(ns_lwdmanager_create(mctx, lwres, &lwresd));
00819 
00820                 port = lwresd_g_listenport;
00821                 if (port == 0)
00822                         port = LWRES_UDP_PORT;
00823 
00824                 listenerslist = NULL;
00825                 (void)cfg_map_get(lwres, "listen-on", &listenerslist);
00826                 if (listenerslist == NULL) {
00827                         struct in_addr localhost;
00828                         isc_sockaddr_t address;
00829 
00830                         localhost.s_addr = htonl(INADDR_LOOPBACK);
00831                         isc_sockaddr_fromin(&address, &localhost, port);
00832                         CHECK(configure_listener(&address, lwresd, mctx,
00833                                                  &newlisteners));
00834                 } else {
00835                         isc_uint32_t i;
00836 
00837                         CHECK(ns_config_getiplist(config, listenerslist,
00838                                                   port, mctx, &addrs, NULL,
00839                                                   &count));
00840                         for (i = 0; i < count; i++)
00841                                 CHECK(configure_listener(&addrs[i], lwresd,
00842                                                          mctx, &newlisteners));
00843                         ns_config_putiplist(mctx, &addrs, NULL, count);
00844                 }
00845                 ns_lwdmanager_detach(&lwresd);
00846         }
00847 
00848         /*
00849          * Shutdown everything on the listeners list, and remove them from
00850          * the list.  Then put all of the new listeners on it.
00851          */
00852 
00853         while (!ISC_LIST_EMPTY(listeners)) {
00854                 listener = ISC_LIST_HEAD(listeners);
00855                 ISC_LIST_UNLINK(listeners, listener, link);
00856 
00857                 isc_sockaddr_format(&listener->address,
00858                                     socktext, sizeof(socktext));
00859 
00860                 listener_shutdown(listener);
00861                 ns_lwreslistener_detach(&listener);
00862 
00863                 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
00864                               NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE,
00865                               "lwres no longer listening on %s", socktext);
00866         }
00867 
00868  cleanup:
00869         ISC_LIST_APPENDLIST(listeners, newlisteners, link);
00870 
00871         if (addrs != NULL)
00872                 ns_config_putiplist(mctx, &addrs, NULL, count);
00873 
00874         if (lwresd != NULL)
00875                 ns_lwdmanager_detach(&lwresd);
00876 
00877         UNLOCK(&listeners_lock);
00878 
00879         return (result);
00880 }
00881 
00882 void
00883 ns_lwresd_shutdown(void) {
00884         ns_lwreslistener_t *listener;
00885 
00886         RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
00887 
00888         while (!ISC_LIST_EMPTY(listeners)) {
00889                 listener = ISC_LIST_HEAD(listeners);
00890                 ISC_LIST_UNLINK(listeners, listener, link);
00891                 ns_lwreslistener_detach(&listener);
00892         }
00893 }

Generated on Tue Apr 28 17:40:54 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha