server.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-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 /*! \file */
00019 
00020 #include <config.h>
00021 
00022 #include <stdlib.h>
00023 #include <unistd.h>
00024 #include <limits.h>
00025 #include <ctype.h>
00026 #include <sys/types.h>
00027 #include <sys/stat.h>
00028 
00029 #include <isc/app.h>
00030 #include <isc/base64.h>
00031 #include <isc/dir.h>
00032 #include <isc/entropy.h>
00033 #include <isc/file.h>
00034 #include <isc/hash.h>
00035 #include <isc/hex.h>
00036 #include <isc/httpd.h>
00037 #include <isc/lex.h>
00038 #include <isc/parseint.h>
00039 #include <isc/portset.h>
00040 #include <isc/print.h>
00041 #include <isc/random.h>
00042 #include <isc/refcount.h>
00043 #include <isc/resource.h>
00044 #include <isc/sha2.h>
00045 #include <isc/socket.h>
00046 #include <isc/stat.h>
00047 #include <isc/stats.h>
00048 #include <isc/stdio.h>
00049 #include <isc/string.h>
00050 #include <isc/task.h>
00051 #include <isc/timer.h>
00052 #include <isc/util.h>
00053 #include <isc/xml.h>
00054 
00055 #ifdef AES_SIT
00056 #include <isc/aes.h>
00057 #else
00058 #include <isc/hmacsha.h>
00059 #endif
00060 
00061 #include <isccfg/grammar.h>
00062 #include <isccfg/namedconf.h>
00063 
00064 #include <bind9/check.h>
00065 
00066 #include <dns/acache.h>
00067 #include <dns/adb.h>
00068 #include <dns/badcache.h>
00069 #include <dns/cache.h>
00070 #include <dns/db.h>
00071 #include <dns/dispatch.h>
00072 #include <dns/dlz.h>
00073 #include <dns/dns64.h>
00074 #include <dns/forward.h>
00075 #include <dns/journal.h>
00076 #include <dns/keytable.h>
00077 #include <dns/keyvalues.h>
00078 #include <dns/lib.h>
00079 #include <dns/master.h>
00080 #include <dns/masterdump.h>
00081 #include <dns/nta.h>
00082 #include <dns/order.h>
00083 #include <dns/peer.h>
00084 #include <dns/portlist.h>
00085 #include <dns/private.h>
00086 #include <dns/rbt.h>
00087 #include <dns/rdataclass.h>
00088 #include <dns/rdatalist.h>
00089 #include <dns/rdataset.h>
00090 #include <dns/rdatastruct.h>
00091 #include <dns/resolver.h>
00092 #include <dns/rootns.h>
00093 #include <dns/rriterator.h>
00094 #include <dns/secalg.h>
00095 #include <dns/soa.h>
00096 #include <dns/stats.h>
00097 #include <dns/tkey.h>
00098 #include <dns/tsig.h>
00099 #include <dns/ttl.h>
00100 #include <dns/view.h>
00101 #include <dns/zone.h>
00102 #include <dns/zt.h>
00103 
00104 #include <dst/dst.h>
00105 #include <dst/result.h>
00106 
00107 #include <named/client.h>
00108 #include <named/config.h>
00109 #include <named/control.h>
00110 #include <named/geoip.h>
00111 #include <named/interfacemgr.h>
00112 #include <named/log.h>
00113 #include <named/logconf.h>
00114 #include <named/lwresd.h>
00115 #include <named/main.h>
00116 #include <named/os.h>
00117 #include <named/server.h>
00118 #include <named/statschannel.h>
00119 #include <named/tkeyconf.h>
00120 #include <named/tsigconf.h>
00121 #include <named/zoneconf.h>
00122 #ifdef HAVE_LIBSCF
00123 #include <named/ns_smf_globals.h>
00124 #include <stdlib.h>
00125 #endif
00126 #ifdef HAVE_GEOIP
00127 #include <named/geoip.h>
00128 #endif /* HAVE_GEOIP */
00129 
00130 #ifndef PATH_MAX
00131 #define PATH_MAX 1024
00132 #endif
00133 
00134 #ifndef SIZE_MAX
00135 #define SIZE_MAX ((size_t)-1)
00136 #endif
00137 
00138 #ifdef TUNE_LARGE
00139 #define RESOLVER_NTASKS 523
00140 #define UDPBUFFERS 32768
00141 #define EXCLBUFFERS 32768
00142 #else
00143 #define RESOLVER_NTASKS 31
00144 #define UDPBUFFERS 1000
00145 #define EXCLBUFFERS 4096
00146 #endif /* TUNE_LARGE */
00147 
00148 /*%
00149  * Check an operation for failure.  Assumes that the function
00150  * using it has a 'result' variable and a 'cleanup' label.
00151  */
00152 #define CHECK(op) \
00153         do { result = (op);                                      \
00154                if (result != ISC_R_SUCCESS) goto cleanup;        \
00155         } while (0)
00156 
00157 #define TCHECK(op) \
00158         do { tresult = (op);                                     \
00159                 if (tresult != ISC_R_SUCCESS) {                  \
00160                         isc_buffer_clear(*text);                 \
00161                         goto cleanup;                            \
00162                 }                                                \
00163         } while (0)
00164 
00165 #define CHECKM(op, msg) \
00166         do { result = (op);                                       \
00167                if (result != ISC_R_SUCCESS) {                     \
00168                         isc_log_write(ns_g_lctx,                  \
00169                                       NS_LOGCATEGORY_GENERAL,     \
00170                                       NS_LOGMODULE_SERVER,        \
00171                                       ISC_LOG_ERROR,              \
00172                                       "%s: %s", msg,              \
00173                                       isc_result_totext(result)); \
00174                         goto cleanup;                             \
00175                 }                                                 \
00176         } while (0)                                               \
00177 
00178 #define CHECKMF(op, msg, file) \
00179         do { result = (op);                                       \
00180                if (result != ISC_R_SUCCESS) {                     \
00181                         isc_log_write(ns_g_lctx,                  \
00182                                       NS_LOGCATEGORY_GENERAL,     \
00183                                       NS_LOGMODULE_SERVER,        \
00184                                       ISC_LOG_ERROR,              \
00185                                       "%s '%s': %s", msg, file,   \
00186                                       isc_result_totext(result)); \
00187                         goto cleanup;                             \
00188                 }                                                 \
00189         } while (0)                                               \
00190 
00191 #define CHECKFATAL(op, msg) \
00192         do { result = (op);                                       \
00193                if (result != ISC_R_SUCCESS)                       \
00194                         fatal(msg, result);                       \
00195         } while (0)                                               \
00196 
00197 /*%
00198  * Maximum ADB size for views that share a cache.  Use this limit to suppress
00199  * the total of memory footprint, which should be the main reason for sharing
00200  * a cache.  Only effective when a finite max-cache-size is specified.
00201  * This is currently defined to be 8MB.
00202  */
00203 #define MAX_ADB_SIZE_FOR_CACHESHARE     8388608U
00204 
00205 struct ns_dispatch {
00206         isc_sockaddr_t                  addr;
00207         unsigned int                    dispatchgen;
00208         dns_dispatch_t                  *dispatch;
00209         ISC_LINK(struct ns_dispatch)    link;
00210 };
00211 
00212 struct ns_cache {
00213         dns_cache_t                     *cache;
00214         dns_view_t                      *primaryview;
00215         isc_boolean_t                   needflush;
00216         isc_boolean_t                   adbsizeadjusted;
00217         ISC_LINK(ns_cache_t)            link;
00218 };
00219 
00220 struct dumpcontext {
00221         isc_mem_t                       *mctx;
00222         isc_boolean_t                   dumpcache;
00223         isc_boolean_t                   dumpzones;
00224         FILE                            *fp;
00225         ISC_LIST(struct viewlistentry)  viewlist;
00226         struct viewlistentry            *view;
00227         struct zonelistentry            *zone;
00228         dns_dumpctx_t                   *mdctx;
00229         dns_db_t                        *db;
00230         dns_db_t                        *cache;
00231         isc_task_t                      *task;
00232         dns_dbversion_t                 *version;
00233 };
00234 
00235 struct viewlistentry {
00236         dns_view_t                      *view;
00237         ISC_LINK(struct viewlistentry)  link;
00238         ISC_LIST(struct zonelistentry)  zonelist;
00239 };
00240 
00241 struct zonelistentry {
00242         dns_zone_t                      *zone;
00243         ISC_LINK(struct zonelistentry)  link;
00244 };
00245 
00246 /*%
00247  * Configuration context to retain for each view that allows
00248  * new zones to be added at runtime.
00249  */
00250 typedef struct ns_cfgctx {
00251         isc_mem_t *                     mctx;
00252         cfg_parser_t *                  conf_parser;
00253         cfg_parser_t *                  add_parser;
00254         cfg_obj_t *                     config;
00255         cfg_obj_t *                     vconfig;
00256         cfg_obj_t *                     nzconfig;
00257         cfg_aclconfctx_t *              actx;
00258 } ns_cfgctx_t;
00259 
00260 /*%
00261  * Holds state information for the initial zone loading process.
00262  * Uses the isc_refcount structure to count the number of views
00263  * with pending zone loads, dereferencing as each view finishes.
00264  */
00265 typedef struct {
00266                 ns_server_t *server;
00267                 isc_refcount_t refs;
00268 } ns_zoneload_t;
00269 
00270 /*
00271  * These zones should not leak onto the Internet.
00272  */
00273 const char *empty_zones[] = {
00274         /* RFC 1918 */
00275         "10.IN-ADDR.ARPA",
00276         "16.172.IN-ADDR.ARPA",
00277         "17.172.IN-ADDR.ARPA",
00278         "18.172.IN-ADDR.ARPA",
00279         "19.172.IN-ADDR.ARPA",
00280         "20.172.IN-ADDR.ARPA",
00281         "21.172.IN-ADDR.ARPA",
00282         "22.172.IN-ADDR.ARPA",
00283         "23.172.IN-ADDR.ARPA",
00284         "24.172.IN-ADDR.ARPA",
00285         "25.172.IN-ADDR.ARPA",
00286         "26.172.IN-ADDR.ARPA",
00287         "27.172.IN-ADDR.ARPA",
00288         "28.172.IN-ADDR.ARPA",
00289         "29.172.IN-ADDR.ARPA",
00290         "30.172.IN-ADDR.ARPA",
00291         "31.172.IN-ADDR.ARPA",
00292         "168.192.IN-ADDR.ARPA",
00293 
00294         /* RFC 6598 */
00295         "64.100.IN-ADDR.ARPA",
00296         "65.100.IN-ADDR.ARPA",
00297         "66.100.IN-ADDR.ARPA",
00298         "67.100.IN-ADDR.ARPA",
00299         "68.100.IN-ADDR.ARPA",
00300         "69.100.IN-ADDR.ARPA",
00301         "70.100.IN-ADDR.ARPA",
00302         "71.100.IN-ADDR.ARPA",
00303         "72.100.IN-ADDR.ARPA",
00304         "73.100.IN-ADDR.ARPA",
00305         "74.100.IN-ADDR.ARPA",
00306         "75.100.IN-ADDR.ARPA",
00307         "76.100.IN-ADDR.ARPA",
00308         "77.100.IN-ADDR.ARPA",
00309         "78.100.IN-ADDR.ARPA",
00310         "79.100.IN-ADDR.ARPA",
00311         "80.100.IN-ADDR.ARPA",
00312         "81.100.IN-ADDR.ARPA",
00313         "82.100.IN-ADDR.ARPA",
00314         "83.100.IN-ADDR.ARPA",
00315         "84.100.IN-ADDR.ARPA",
00316         "85.100.IN-ADDR.ARPA",
00317         "86.100.IN-ADDR.ARPA",
00318         "87.100.IN-ADDR.ARPA",
00319         "88.100.IN-ADDR.ARPA",
00320         "89.100.IN-ADDR.ARPA",
00321         "90.100.IN-ADDR.ARPA",
00322         "91.100.IN-ADDR.ARPA",
00323         "92.100.IN-ADDR.ARPA",
00324         "93.100.IN-ADDR.ARPA",
00325         "94.100.IN-ADDR.ARPA",
00326         "95.100.IN-ADDR.ARPA",
00327         "96.100.IN-ADDR.ARPA",
00328         "97.100.IN-ADDR.ARPA",
00329         "98.100.IN-ADDR.ARPA",
00330         "99.100.IN-ADDR.ARPA",
00331         "100.100.IN-ADDR.ARPA",
00332         "101.100.IN-ADDR.ARPA",
00333         "102.100.IN-ADDR.ARPA",
00334         "103.100.IN-ADDR.ARPA",
00335         "104.100.IN-ADDR.ARPA",
00336         "105.100.IN-ADDR.ARPA",
00337         "106.100.IN-ADDR.ARPA",
00338         "107.100.IN-ADDR.ARPA",
00339         "108.100.IN-ADDR.ARPA",
00340         "109.100.IN-ADDR.ARPA",
00341         "110.100.IN-ADDR.ARPA",
00342         "111.100.IN-ADDR.ARPA",
00343         "112.100.IN-ADDR.ARPA",
00344         "113.100.IN-ADDR.ARPA",
00345         "114.100.IN-ADDR.ARPA",
00346         "115.100.IN-ADDR.ARPA",
00347         "116.100.IN-ADDR.ARPA",
00348         "117.100.IN-ADDR.ARPA",
00349         "118.100.IN-ADDR.ARPA",
00350         "119.100.IN-ADDR.ARPA",
00351         "120.100.IN-ADDR.ARPA",
00352         "121.100.IN-ADDR.ARPA",
00353         "122.100.IN-ADDR.ARPA",
00354         "123.100.IN-ADDR.ARPA",
00355         "124.100.IN-ADDR.ARPA",
00356         "125.100.IN-ADDR.ARPA",
00357         "126.100.IN-ADDR.ARPA",
00358         "127.100.IN-ADDR.ARPA",
00359 
00360         /* RFC 5735 and RFC 5737 */
00361         "0.IN-ADDR.ARPA",       /* THIS NETWORK */
00362         "127.IN-ADDR.ARPA",     /* LOOPBACK */
00363         "254.169.IN-ADDR.ARPA", /* LINK LOCAL */
00364         "2.0.192.IN-ADDR.ARPA", /* TEST NET */
00365         "100.51.198.IN-ADDR.ARPA",      /* TEST NET 2 */
00366         "113.0.203.IN-ADDR.ARPA",       /* TEST NET 3 */
00367         "255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
00368 
00369         /* Local IPv6 Unicast Addresses */
00370         "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
00371         "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
00372         /* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
00373         "D.F.IP6.ARPA",
00374         "8.E.F.IP6.ARPA",       /* LINK LOCAL */
00375         "9.E.F.IP6.ARPA",       /* LINK LOCAL */
00376         "A.E.F.IP6.ARPA",       /* LINK LOCAL */
00377         "B.E.F.IP6.ARPA",       /* LINK LOCAL */
00378 
00379         /* Example Prefix, RFC 3849. */
00380         "8.B.D.0.1.0.0.2.IP6.ARPA",
00381 
00382         NULL
00383 };
00384 
00385 ISC_PLATFORM_NORETURN_PRE static void
00386 fatal(const char *msg, isc_result_t result) ISC_PLATFORM_NORETURN_POST;
00387 
00388 static void
00389 ns_server_reload(isc_task_t *task, isc_event_t *event);
00390 
00391 static isc_result_t
00392 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
00393                         cfg_aclconfctx_t *actx, isc_mem_t *mctx,
00394                         isc_uint16_t family, ns_listenelt_t **target);
00395 static isc_result_t
00396 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
00397                          cfg_aclconfctx_t *actx, isc_mem_t *mctx,
00398                          isc_uint16_t family, ns_listenlist_t **target);
00399 
00400 static isc_result_t
00401 configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
00402                   const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype);
00403 
00404 static isc_result_t
00405 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
00406                      const cfg_obj_t *alternates);
00407 
00408 static isc_result_t
00409 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
00410                const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
00411                dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
00412                isc_boolean_t added, isc_boolean_t old_rpz_ok,
00413                isc_boolean_t modify);
00414 
00415 static isc_result_t
00416 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
00417 
00418 static void
00419 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
00420 
00421 static void
00422 newzone_cfgctx_destroy(void **cfgp);
00423 
00424 static inline isc_result_t
00425 putstr(isc_buffer_t **b, const char *str);
00426 
00427 static isc_result_t
00428 putmem(isc_buffer_t **b, const char *str, size_t len);
00429 
00430 static isc_result_t
00431 putuint8(isc_buffer_t **b, isc_uint8_t val);
00432 
00433 static inline isc_result_t
00434 putnull(isc_buffer_t **b);
00435 
00436 static isc_result_t
00437 add_comment(FILE *fp, const char *viewname);
00438 
00439 /*%
00440  * Configure a single view ACL at '*aclp'.  Get its configuration from
00441  * 'vconfig' (for per-view configuration) and maybe from 'config'
00442  */
00443 static isc_result_t
00444 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
00445                    const char *aclname, const char *acltuplename,
00446                    cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp)
00447 {
00448         isc_result_t result;
00449         const cfg_obj_t *maps[3];
00450         const cfg_obj_t *aclobj = NULL;
00451         int i = 0;
00452 
00453         if (*aclp != NULL)
00454                 dns_acl_detach(aclp);
00455         if (vconfig != NULL)
00456                 maps[i++] = cfg_tuple_get(vconfig, "options");
00457         if (config != NULL) {
00458                 const cfg_obj_t *options = NULL;
00459                 (void)cfg_map_get(config, "options", &options);
00460                 if (options != NULL)
00461                         maps[i++] = options;
00462         }
00463         maps[i] = NULL;
00464 
00465         (void)ns_config_get(maps, aclname, &aclobj);
00466         if (aclobj == NULL)
00467                 /*
00468                  * No value available.  *aclp == NULL.
00469                  */
00470                 return (ISC_R_SUCCESS);
00471 
00472         if (acltuplename != NULL) {
00473                 /*
00474                  * If the ACL is given in an optional tuple, retrieve it.
00475                  * The parser should have ensured that a valid object be
00476                  * returned.
00477                  */
00478                 aclobj = cfg_tuple_get(aclobj, acltuplename);
00479         }
00480 
00481         result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
00482                                     actx, mctx, 0, aclp);
00483 
00484         return (result);
00485 }
00486 
00487 /*%
00488  * Configure a sortlist at '*aclp'.  Essentially the same as
00489  * configure_view_acl() except it calls cfg_acl_fromconfig with a
00490  * nest_level value of 2.
00491  */
00492 static isc_result_t
00493 configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
00494                         cfg_aclconfctx_t *actx, isc_mem_t *mctx,
00495                         dns_acl_t **aclp)
00496 {
00497         isc_result_t result;
00498         const cfg_obj_t *maps[3];
00499         const cfg_obj_t *aclobj = NULL;
00500         int i = 0;
00501 
00502         if (*aclp != NULL)
00503                 dns_acl_detach(aclp);
00504         if (vconfig != NULL)
00505                 maps[i++] = cfg_tuple_get(vconfig, "options");
00506         if (config != NULL) {
00507                 const cfg_obj_t *options = NULL;
00508                 (void)cfg_map_get(config, "options", &options);
00509                 if (options != NULL)
00510                         maps[i++] = options;
00511         }
00512         maps[i] = NULL;
00513 
00514         (void)ns_config_get(maps, "sortlist", &aclobj);
00515         if (aclobj == NULL)
00516                 return (ISC_R_SUCCESS);
00517 
00518         /*
00519          * Use a nest level of 3 for the "top level" of the sortlist;
00520          * this means each entry in the top three levels will be stored
00521          * as lists of separate, nested ACLs, rather than merged together
00522          * into IP tables as is usually done with ACLs.
00523          */
00524         result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
00525                                     actx, mctx, 3, aclp);
00526 
00527         return (result);
00528 }
00529 
00530 static isc_result_t
00531 configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
00532                          const char *confname, const char *conftuplename,
00533                          isc_mem_t *mctx, dns_rbt_t **rbtp)
00534 {
00535         isc_result_t result;
00536         const cfg_obj_t *maps[3];
00537         const cfg_obj_t *obj = NULL;
00538         const cfg_listelt_t *element;
00539         int i = 0;
00540         dns_fixedname_t fixed;
00541         dns_name_t *name;
00542         isc_buffer_t b;
00543         const char *str;
00544         const cfg_obj_t *nameobj;
00545 
00546         if (*rbtp != NULL)
00547                 dns_rbt_destroy(rbtp);
00548         if (vconfig != NULL)
00549                 maps[i++] = cfg_tuple_get(vconfig, "options");
00550         if (config != NULL) {
00551                 const cfg_obj_t *options = NULL;
00552                 (void)cfg_map_get(config, "options", &options);
00553                 if (options != NULL)
00554                         maps[i++] = options;
00555         }
00556         maps[i] = NULL;
00557 
00558         (void)ns_config_get(maps, confname, &obj);
00559         if (obj == NULL)
00560                 /*
00561                  * No value available.  *rbtp == NULL.
00562                  */
00563                 return (ISC_R_SUCCESS);
00564 
00565         if (conftuplename != NULL) {
00566                 obj = cfg_tuple_get(obj, conftuplename);
00567                 if (cfg_obj_isvoid(obj))
00568                         return (ISC_R_SUCCESS);
00569         }
00570 
00571         result = dns_rbt_create(mctx, NULL, NULL, rbtp);
00572         if (result != ISC_R_SUCCESS)
00573                 return (result);
00574 
00575         dns_fixedname_init(&fixed);
00576         name = dns_fixedname_name(&fixed);
00577         for (element = cfg_list_first(obj);
00578              element != NULL;
00579              element = cfg_list_next(element)) {
00580                 nameobj = cfg_listelt_value(element);
00581                 str = cfg_obj_asstring(nameobj);
00582                 isc_buffer_constinit(&b, str, strlen(str));
00583                 isc_buffer_add(&b, strlen(str));
00584                 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
00585                 /*
00586                  * We don't need the node data, but need to set dummy data to
00587                  * avoid a partial match with an empty node.  For example, if
00588                  * we have foo.example.com and bar.example.com, we'd get a match
00589                  * for baz.example.com, which is not the expected result.
00590                  * We simply use (void *)1 as the dummy data.
00591                  */
00592                 result = dns_rbt_addname(*rbtp, name, (void *)1);
00593                 if (result != ISC_R_SUCCESS) {
00594                         cfg_obj_log(nameobj, ns_g_lctx, ISC_LOG_ERROR,
00595                                     "failed to add %s for %s: %s",
00596                                     str, confname, isc_result_totext(result));
00597                         goto cleanup;
00598                 }
00599 
00600         }
00601 
00602         return (result);
00603 
00604   cleanup:
00605         dns_rbt_destroy(rbtp);
00606         return (result);
00607 
00608 }
00609 
00610 static isc_result_t
00611 dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
00612                   isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx)
00613 {
00614         dns_rdataclass_t viewclass;
00615         dns_rdata_dnskey_t keystruct;
00616         isc_uint32_t flags, proto, alg;
00617         const char *keystr, *keynamestr;
00618         unsigned char keydata[4096];
00619         isc_buffer_t keydatabuf;
00620         unsigned char rrdata[4096];
00621         isc_buffer_t rrdatabuf;
00622         isc_region_t r;
00623         dns_fixedname_t fkeyname;
00624         dns_name_t *keyname;
00625         isc_buffer_t namebuf;
00626         isc_result_t result;
00627         dst_key_t *dstkey = NULL;
00628 
00629         INSIST(target != NULL && *target == NULL);
00630 
00631         flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
00632         proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
00633         alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
00634         keyname = dns_fixedname_name(&fkeyname);
00635         keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
00636 
00637         if (managed) {
00638                 const char *initmethod;
00639                 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
00640 
00641                 if (strcasecmp(initmethod, "initial-key") != 0) {
00642                         cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
00643                                     "managed key '%s': "
00644                                     "invalid initialization method '%s'",
00645                                     keynamestr, initmethod);
00646                         result = ISC_R_FAILURE;
00647                         goto cleanup;
00648                 }
00649         }
00650 
00651         if (vconfig == NULL)
00652                 viewclass = dns_rdataclass_in;
00653         else {
00654                 const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
00655                 CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
00656                                          &viewclass));
00657         }
00658         keystruct.common.rdclass = viewclass;
00659         keystruct.common.rdtype = dns_rdatatype_dnskey;
00660         /*
00661          * The key data in keystruct is not dynamically allocated.
00662          */
00663         keystruct.mctx = NULL;
00664 
00665         ISC_LINK_INIT(&keystruct.common, link);
00666 
00667         if (flags > 0xffff)
00668                 CHECKM(ISC_R_RANGE, "key flags");
00669         if (proto > 0xff)
00670                 CHECKM(ISC_R_RANGE, "key protocol");
00671         if (alg > 0xff)
00672                 CHECKM(ISC_R_RANGE, "key algorithm");
00673         keystruct.flags = (isc_uint16_t)flags;
00674         keystruct.protocol = (isc_uint8_t)proto;
00675         keystruct.algorithm = (isc_uint8_t)alg;
00676 
00677         isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
00678         isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
00679 
00680         keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
00681         CHECK(isc_base64_decodestring(keystr, &keydatabuf));
00682         isc_buffer_usedregion(&keydatabuf, &r);
00683         keystruct.datalen = r.length;
00684         keystruct.data = r.base;
00685 
00686         if ((keystruct.algorithm == DST_ALG_RSASHA1 ||
00687              keystruct.algorithm == DST_ALG_RSAMD5) &&
00688             r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
00689                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
00690                             "%s key '%s' has a weak exponent",
00691                             managed ? "managed" : "trusted",
00692                             keynamestr);
00693 
00694         CHECK(dns_rdata_fromstruct(NULL,
00695                                    keystruct.common.rdclass,
00696                                    keystruct.common.rdtype,
00697                                    &keystruct, &rrdatabuf));
00698         dns_fixedname_init(&fkeyname);
00699         isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr));
00700         isc_buffer_add(&namebuf, strlen(keynamestr));
00701         CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL));
00702         CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
00703                               mctx, &dstkey));
00704 
00705         *target = dstkey;
00706         return (ISC_R_SUCCESS);
00707 
00708  cleanup:
00709         if (result == DST_R_NOCRYPTO) {
00710                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
00711                             "ignoring %s key for '%s': no crypto support",
00712                             managed ? "managed" : "trusted",
00713                             keynamestr);
00714         } else if (result == DST_R_UNSUPPORTEDALG) {
00715                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
00716                             "skipping %s key for '%s': %s",
00717                             managed ? "managed" : "trusted",
00718                             keynamestr, isc_result_totext(result));
00719         } else {
00720                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
00721                             "configuring %s key for '%s': %s",
00722                             managed ? "managed" : "trusted",
00723                             keynamestr, isc_result_totext(result));
00724                 result = ISC_R_FAILURE;
00725         }
00726 
00727         if (dstkey != NULL)
00728                 dst_key_free(&dstkey);
00729 
00730         return (result);
00731 }
00732 
00733 static isc_result_t
00734 load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
00735                dns_view_t *view, isc_boolean_t managed,
00736                dns_name_t *keyname, isc_mem_t *mctx)
00737 {
00738         const cfg_listelt_t *elt, *elt2;
00739         const cfg_obj_t *key, *keylist;
00740         dst_key_t *dstkey = NULL;
00741         isc_result_t result;
00742         dns_keytable_t *secroots = NULL;
00743 
00744         CHECK(dns_view_getsecroots(view, &secroots));
00745 
00746         for (elt = cfg_list_first(keys);
00747              elt != NULL;
00748              elt = cfg_list_next(elt)) {
00749                 keylist = cfg_listelt_value(elt);
00750 
00751                 for (elt2 = cfg_list_first(keylist);
00752                      elt2 != NULL;
00753                      elt2 = cfg_list_next(elt2)) {
00754                         key = cfg_listelt_value(elt2);
00755                         result = dstkey_fromconfig(vconfig, key, managed,
00756                                                    &dstkey, mctx);
00757                         if (result ==  DST_R_UNSUPPORTEDALG) {
00758                                 result = ISC_R_SUCCESS;
00759                                 continue;
00760                         }
00761                         if (result != ISC_R_SUCCESS)
00762                                 goto cleanup;
00763 
00764                         /*
00765                          * If keyname was specified, we only add that key.
00766                          */
00767                         if (keyname != NULL &&
00768                             !dns_name_equal(keyname, dst_key_name(dstkey)))
00769                         {
00770                                 dst_key_free(&dstkey);
00771                                 continue;
00772                         }
00773 
00774                         CHECK(dns_keytable_add(secroots, managed, &dstkey));
00775                 }
00776         }
00777 
00778  cleanup:
00779         if (dstkey != NULL)
00780                 dst_key_free(&dstkey);
00781         if (secroots != NULL)
00782                 dns_keytable_detach(&secroots);
00783         if (result == DST_R_NOCRYPTO)
00784                 result = ISC_R_SUCCESS;
00785         return (result);
00786 }
00787 
00788 /*%
00789  * Configure DNSSEC keys for a view.
00790  *
00791  * The per-view configuration values and the server-global defaults are read
00792  * from 'vconfig' and 'config'.
00793  */
00794 static isc_result_t
00795 configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
00796                           const cfg_obj_t *config, const cfg_obj_t *bindkeys,
00797                           isc_boolean_t auto_dlv, isc_boolean_t auto_root,
00798                           isc_mem_t *mctx)
00799 {
00800         isc_result_t result = ISC_R_SUCCESS;
00801         const cfg_obj_t *view_keys = NULL;
00802         const cfg_obj_t *global_keys = NULL;
00803         const cfg_obj_t *view_managed_keys = NULL;
00804         const cfg_obj_t *global_managed_keys = NULL;
00805         const cfg_obj_t *maps[4];
00806         const cfg_obj_t *voptions = NULL;
00807         const cfg_obj_t *options = NULL;
00808         const cfg_obj_t *obj = NULL;
00809         const char *directory;
00810         int i = 0;
00811 
00812         /* We don't need trust anchors for the _bind view */
00813         if (strcmp(view->name, "_bind") == 0 &&
00814             view->rdclass == dns_rdataclass_chaos) {
00815                 return (ISC_R_SUCCESS);
00816         }
00817 
00818         if (vconfig != NULL) {
00819                 voptions = cfg_tuple_get(vconfig, "options");
00820                 if (voptions != NULL) {
00821                         (void) cfg_map_get(voptions, "trusted-keys",
00822                                            &view_keys);
00823                         (void) cfg_map_get(voptions, "managed-keys",
00824                                            &view_managed_keys);
00825                         maps[i++] = voptions;
00826                 }
00827         }
00828 
00829         if (config != NULL) {
00830                 (void)cfg_map_get(config, "trusted-keys", &global_keys);
00831                 (void)cfg_map_get(config, "managed-keys", &global_managed_keys);
00832                 (void)cfg_map_get(config, "options", &options);
00833                 if (options != NULL) {
00834                         maps[i++] = options;
00835                 }
00836         }
00837 
00838         maps[i++] = ns_g_defaults;
00839         maps[i] = NULL;
00840 
00841         result = dns_view_initsecroots(view, mctx);
00842         if (result != ISC_R_SUCCESS) {
00843                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00844                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
00845                               "couldn't create keytable");
00846                 return (ISC_R_UNEXPECTED);
00847         }
00848 
00849         result = dns_view_initntatable(view, ns_g_taskmgr, ns_g_timermgr);
00850         if (result != ISC_R_SUCCESS) {
00851                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00852                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
00853                               "couldn't create NTA table");
00854                 return (ISC_R_UNEXPECTED);
00855         }
00856 
00857         if (auto_dlv && view->rdclass == dns_rdataclass_in) {
00858                 const cfg_obj_t *builtin_keys = NULL;
00859                 const cfg_obj_t *builtin_managed_keys = NULL;
00860 
00861                 isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
00862                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
00863                               "using built-in DLV key for view %s",
00864                               view->name);
00865 
00866                 /*
00867                  * If bind.keys exists, it overrides the managed-keys
00868                  * clause hard-coded in ns_g_config.
00869                  */
00870                 if (bindkeys != NULL) {
00871                         (void)cfg_map_get(bindkeys, "trusted-keys",
00872                                           &builtin_keys);
00873                         (void)cfg_map_get(bindkeys, "managed-keys",
00874                                           &builtin_managed_keys);
00875                 } else {
00876                         (void)cfg_map_get(ns_g_config, "trusted-keys",
00877                                           &builtin_keys);
00878                         (void)cfg_map_get(ns_g_config, "managed-keys",
00879                                           &builtin_managed_keys);
00880                 }
00881 
00882                 if (builtin_keys != NULL)
00883                         CHECK(load_view_keys(builtin_keys, vconfig, view,
00884                                              ISC_FALSE, view->dlv, mctx));
00885                 if (builtin_managed_keys != NULL)
00886                         CHECK(load_view_keys(builtin_managed_keys, vconfig,
00887                                              view, ISC_TRUE, view->dlv, mctx));
00888         }
00889 
00890         if (auto_root && view->rdclass == dns_rdataclass_in) {
00891                 const cfg_obj_t *builtin_keys = NULL;
00892                 const cfg_obj_t *builtin_managed_keys = NULL;
00893 
00894                 isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
00895                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
00896                               "using built-in root key for view %s",
00897                               view->name);
00898 
00899                 /*
00900                  * If bind.keys exists, it overrides the managed-keys
00901                  * clause hard-coded in ns_g_config.
00902                  */
00903                 if (bindkeys != NULL) {
00904                         (void)cfg_map_get(bindkeys, "trusted-keys",
00905                                           &builtin_keys);
00906                         (void)cfg_map_get(bindkeys, "managed-keys",
00907                                           &builtin_managed_keys);
00908                 } else {
00909                         (void)cfg_map_get(ns_g_config, "trusted-keys",
00910                                           &builtin_keys);
00911                         (void)cfg_map_get(ns_g_config, "managed-keys",
00912                                           &builtin_managed_keys);
00913                 }
00914 
00915                 if (builtin_keys != NULL)
00916                         CHECK(load_view_keys(builtin_keys, vconfig, view,
00917                                              ISC_FALSE, dns_rootname, mctx));
00918                 if (builtin_managed_keys != NULL)
00919                         CHECK(load_view_keys(builtin_managed_keys, vconfig,
00920                                              view, ISC_TRUE, dns_rootname,
00921                                              mctx));
00922         }
00923 
00924         CHECK(load_view_keys(view_keys, vconfig, view, ISC_FALSE,
00925                              NULL, mctx));
00926         CHECK(load_view_keys(view_managed_keys, vconfig, view, ISC_TRUE,
00927                              NULL, mctx));
00928 
00929         if (view->rdclass == dns_rdataclass_in) {
00930                 CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE,
00931                                      NULL, mctx));
00932                 CHECK(load_view_keys(global_managed_keys, vconfig, view,
00933                                      ISC_TRUE, NULL, mctx));
00934         }
00935 
00936         /*
00937          * Add key zone for managed-keys.
00938          */
00939         obj = NULL;
00940         (void)ns_config_get(maps, "managed-keys-directory", &obj);
00941         directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
00942         if (directory != NULL)
00943                 result = isc_file_isdirectory(directory);
00944         if (result != ISC_R_SUCCESS) {
00945                 isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
00946                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
00947                               "invalid managed-keys-directory %s: %s",
00948                               directory, isc_result_totext(result));
00949                 goto cleanup;
00950 
00951         }
00952         CHECK(add_keydata_zone(view, directory, ns_g_mctx));
00953 
00954   cleanup:
00955         return (result);
00956 }
00957 
00958 static isc_result_t
00959 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
00960         const cfg_listelt_t *element;
00961         const cfg_obj_t *obj;
00962         const char *str;
00963         dns_fixedname_t fixed;
00964         dns_name_t *name;
00965         isc_boolean_t value;
00966         isc_result_t result;
00967         isc_buffer_t b;
00968 
00969         dns_fixedname_init(&fixed);
00970         name = dns_fixedname_name(&fixed);
00971         for (element = cfg_list_first(mbs);
00972              element != NULL;
00973              element = cfg_list_next(element))
00974         {
00975                 obj = cfg_listelt_value(element);
00976                 str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
00977                 isc_buffer_constinit(&b, str, strlen(str));
00978                 isc_buffer_add(&b, strlen(str));
00979                 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
00980                 value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
00981                 CHECK(dns_resolver_setmustbesecure(resolver, name, value));
00982         }
00983 
00984         result = ISC_R_SUCCESS;
00985 
00986  cleanup:
00987         return (result);
00988 }
00989 
00990 /*%
00991  * Get a dispatch appropriate for the resolver of a given view.
00992  */
00993 static isc_result_t
00994 get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
00995                               dns_dispatch_t **dispatchp, isc_dscp_t *dscpp,
00996                               isc_boolean_t is_firstview)
00997 {
00998         isc_result_t result = ISC_R_FAILURE;
00999         dns_dispatch_t *disp;
01000         isc_sockaddr_t sa;
01001         unsigned int attrs, attrmask;
01002         const cfg_obj_t *obj = NULL;
01003         unsigned int maxdispatchbuffers = UDPBUFFERS;
01004         isc_dscp_t dscp = -1;
01005 
01006         switch (af) {
01007         case AF_INET:
01008                 result = ns_config_get(maps, "query-source", &obj);
01009                 INSIST(result == ISC_R_SUCCESS);
01010                 break;
01011         case AF_INET6:
01012                 result = ns_config_get(maps, "query-source-v6", &obj);
01013                 INSIST(result == ISC_R_SUCCESS);
01014                 break;
01015         default:
01016                 INSIST(0);
01017         }
01018 
01019         sa = *(cfg_obj_assockaddr(obj));
01020         INSIST(isc_sockaddr_pf(&sa) == af);
01021 
01022         dscp = cfg_obj_getdscp(obj);
01023         if (dscp != -1 && dscpp != NULL)
01024                 *dscpp = dscp;
01025 
01026         /*
01027          * If we don't support this address family, we're done!
01028          */
01029         switch (af) {
01030         case AF_INET:
01031                 result = isc_net_probeipv4();
01032                 break;
01033         case AF_INET6:
01034                 result = isc_net_probeipv6();
01035                 break;
01036         default:
01037                 INSIST(0);
01038         }
01039         if (result != ISC_R_SUCCESS)
01040                 return (ISC_R_SUCCESS);
01041 
01042         /*
01043          * Try to find a dispatcher that we can share.
01044          */
01045         attrs = 0;
01046         attrs |= DNS_DISPATCHATTR_UDP;
01047         switch (af) {
01048         case AF_INET:
01049                 attrs |= DNS_DISPATCHATTR_IPV4;
01050                 break;
01051         case AF_INET6:
01052                 attrs |= DNS_DISPATCHATTR_IPV6;
01053                 break;
01054         }
01055         if (isc_sockaddr_getport(&sa) == 0) {
01056                 attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
01057                 maxdispatchbuffers = EXCLBUFFERS;
01058         } else {
01059                 INSIST(obj != NULL);
01060                 if (is_firstview) {
01061                         cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
01062                                     "using specific query-source port "
01063                                     "suppresses port randomization and can be "
01064                                     "insecure.");
01065                 }
01066         }
01067 
01068         attrmask = 0;
01069         attrmask |= DNS_DISPATCHATTR_UDP;
01070         attrmask |= DNS_DISPATCHATTR_TCP;
01071         attrmask |= DNS_DISPATCHATTR_IPV4;
01072         attrmask |= DNS_DISPATCHATTR_IPV6;
01073 
01074         disp = NULL;
01075         result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
01076                                      ns_g_taskmgr, &sa, 4096,
01077                                      maxdispatchbuffers, 32768, 16411, 16433,
01078                                      attrs, attrmask, &disp);
01079         if (result != ISC_R_SUCCESS) {
01080                 isc_sockaddr_t any;
01081                 char buf[ISC_SOCKADDR_FORMATSIZE];
01082 
01083                 switch (af) {
01084                 case AF_INET:
01085                         isc_sockaddr_any(&any);
01086                         break;
01087                 case AF_INET6:
01088                         isc_sockaddr_any6(&any);
01089                         break;
01090                 }
01091                 if (isc_sockaddr_equal(&sa, &any))
01092                         return (ISC_R_SUCCESS);
01093                 isc_sockaddr_format(&sa, buf, sizeof(buf));
01094                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01095                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
01096                               "could not get query source dispatcher (%s)",
01097                               buf);
01098                 return (result);
01099         }
01100 
01101         *dispatchp = disp;
01102 
01103         return (ISC_R_SUCCESS);
01104 }
01105 
01106 static isc_result_t
01107 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
01108         dns_rdataclass_t rdclass;
01109         dns_rdatatype_t rdtype;
01110         const cfg_obj_t *obj;
01111         dns_fixedname_t fixed;
01112         unsigned int mode = 0;
01113         const char *str;
01114         isc_buffer_t b;
01115         isc_result_t result;
01116         isc_boolean_t addroot;
01117 
01118         result = ns_config_getclass(cfg_tuple_get(ent, "class"),
01119                                     dns_rdataclass_any, &rdclass);
01120         if (result != ISC_R_SUCCESS)
01121                 return (result);
01122 
01123         result = ns_config_gettype(cfg_tuple_get(ent, "type"),
01124                                    dns_rdatatype_any, &rdtype);
01125         if (result != ISC_R_SUCCESS)
01126                 return (result);
01127 
01128         obj = cfg_tuple_get(ent, "name");
01129         if (cfg_obj_isstring(obj))
01130                 str = cfg_obj_asstring(obj);
01131         else
01132                 str = "*";
01133         addroot = ISC_TF(strcmp(str, "*") == 0);
01134         isc_buffer_constinit(&b, str, strlen(str));
01135         isc_buffer_add(&b, strlen(str));
01136         dns_fixedname_init(&fixed);
01137         result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
01138                                    dns_rootname, 0, NULL);
01139         if (result != ISC_R_SUCCESS)
01140                 return (result);
01141 
01142         obj = cfg_tuple_get(ent, "ordering");
01143         INSIST(cfg_obj_isstring(obj));
01144         str = cfg_obj_asstring(obj);
01145         if (!strcasecmp(str, "fixed"))
01146 #if DNS_RDATASET_FIXED
01147                 mode = DNS_RDATASETATTR_FIXEDORDER;
01148 #else
01149                 mode = 0;
01150 #endif /* DNS_RDATASET_FIXED */
01151         else if (!strcasecmp(str, "random"))
01152                 mode = DNS_RDATASETATTR_RANDOMIZE;
01153         else if (!strcasecmp(str, "cyclic"))
01154                 mode = 0;
01155         else
01156                 INSIST(0);
01157 
01158         /*
01159          * "*" should match everything including the root (BIND 8 compat).
01160          * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
01161          * explicit entry for "." when the name is "*".
01162          */
01163         if (addroot) {
01164                 result = dns_order_add(order, dns_rootname,
01165                                        rdtype, rdclass, mode);
01166                 if (result != ISC_R_SUCCESS)
01167                         return (result);
01168         }
01169 
01170         return (dns_order_add(order, dns_fixedname_name(&fixed),
01171                               rdtype, rdclass, mode));
01172 }
01173 
01174 static isc_result_t
01175 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
01176         isc_netaddr_t na;
01177         dns_peer_t *peer;
01178         const cfg_obj_t *obj;
01179         const char *str;
01180         isc_result_t result;
01181         unsigned int prefixlen;
01182 
01183         cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
01184 
01185         peer = NULL;
01186         result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
01187         if (result != ISC_R_SUCCESS)
01188                 return (result);
01189 
01190         obj = NULL;
01191         (void)cfg_map_get(cpeer, "bogus", &obj);
01192         if (obj != NULL)
01193                 CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
01194 
01195         obj = NULL;
01196         (void)cfg_map_get(cpeer, "provide-ixfr", &obj);
01197         if (obj != NULL)
01198                 CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
01199 
01200         obj = NULL;
01201         (void)cfg_map_get(cpeer, "request-expire", &obj);
01202         if (obj != NULL)
01203                 CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
01204 
01205         obj = NULL;
01206         (void)cfg_map_get(cpeer, "request-ixfr", &obj);
01207         if (obj != NULL)
01208                 CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
01209 
01210         obj = NULL;
01211         (void)cfg_map_get(cpeer, "request-nsid", &obj);
01212         if (obj != NULL)
01213                 CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
01214 
01215 #ifdef ISC_PLATFORM_USESIT
01216         obj = NULL;
01217         (void)cfg_map_get(cpeer, "request-sit", &obj);
01218         if (obj != NULL)
01219                 CHECK(dns_peer_setrequestsit(peer, cfg_obj_asboolean(obj)));
01220 #endif
01221 
01222         obj = NULL;
01223         (void)cfg_map_get(cpeer, "edns", &obj);
01224         if (obj != NULL)
01225                 CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
01226 
01227         obj = NULL;
01228         (void)cfg_map_get(cpeer, "edns-udp-size", &obj);
01229         if (obj != NULL) {
01230                 isc_uint32_t udpsize = cfg_obj_asuint32(obj);
01231                 if (udpsize < 512)
01232                         udpsize = 512;
01233                 if (udpsize > 4096)
01234                         udpsize = 4096;
01235                 CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize));
01236         }
01237 
01238         obj = NULL;
01239         (void)cfg_map_get(cpeer, "edns-version", &obj);
01240         if (obj != NULL) {
01241                 isc_uint32_t ednsversion = cfg_obj_asuint32(obj);
01242                 if (ednsversion > 255)
01243                         ednsversion = 255;
01244                 CHECK(dns_peer_setednsversion(peer, (isc_uint8_t)ednsversion));
01245         }
01246 
01247         obj = NULL;
01248         (void)cfg_map_get(cpeer, "max-udp-size", &obj);
01249         if (obj != NULL) {
01250                 isc_uint32_t udpsize = cfg_obj_asuint32(obj);
01251                 if (udpsize < 512)
01252                         udpsize = 512;
01253                 if (udpsize > 4096)
01254                         udpsize = 4096;
01255                 CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize));
01256         }
01257 
01258         obj = NULL;
01259         (void)cfg_map_get(cpeer, "tcp-only", &obj);
01260         if (obj != NULL)
01261                 CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
01262 
01263         obj = NULL;
01264         (void)cfg_map_get(cpeer, "transfers", &obj);
01265         if (obj != NULL)
01266                 CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
01267 
01268         obj = NULL;
01269         (void)cfg_map_get(cpeer, "transfer-format", &obj);
01270         if (obj != NULL) {
01271                 str = cfg_obj_asstring(obj);
01272                 if (strcasecmp(str, "many-answers") == 0)
01273                         CHECK(dns_peer_settransferformat(peer,
01274                                                          dns_many_answers));
01275                 else if (strcasecmp(str, "one-answer") == 0)
01276                         CHECK(dns_peer_settransferformat(peer,
01277                                                          dns_one_answer));
01278                 else
01279                         INSIST(0);
01280         }
01281 
01282         obj = NULL;
01283         (void)cfg_map_get(cpeer, "keys", &obj);
01284         if (obj != NULL) {
01285                 result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
01286                 if (result != ISC_R_SUCCESS)
01287                         goto cleanup;
01288         }
01289 
01290         obj = NULL;
01291         if (na.family == AF_INET)
01292                 (void)cfg_map_get(cpeer, "transfer-source", &obj);
01293         else
01294                 (void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
01295         if (obj != NULL) {
01296                 result = dns_peer_settransfersource(peer,
01297                                                     cfg_obj_assockaddr(obj));
01298                 if (result != ISC_R_SUCCESS)
01299                         goto cleanup;
01300                 result = dns_peer_settransferdscp(peer, cfg_obj_getdscp(obj));
01301                 if (result != ISC_R_SUCCESS)
01302                         goto cleanup;
01303                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
01304         }
01305 
01306         obj = NULL;
01307         if (na.family == AF_INET)
01308                 (void)cfg_map_get(cpeer, "notify-source", &obj);
01309         else
01310                 (void)cfg_map_get(cpeer, "notify-source-v6", &obj);
01311         if (obj != NULL) {
01312                 result = dns_peer_setnotifysource(peer,
01313                                                   cfg_obj_assockaddr(obj));
01314                 if (result != ISC_R_SUCCESS)
01315                         goto cleanup;
01316                 result = dns_peer_setnotifydscp(peer, cfg_obj_getdscp(obj));
01317                 if (result != ISC_R_SUCCESS)
01318                         goto cleanup;
01319                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
01320         }
01321 
01322         obj = NULL;
01323         if (na.family == AF_INET)
01324                 (void)cfg_map_get(cpeer, "query-source", &obj);
01325         else
01326                 (void)cfg_map_get(cpeer, "query-source-v6", &obj);
01327         if (obj != NULL) {
01328                 result = dns_peer_setquerysource(peer,
01329                                                  cfg_obj_assockaddr(obj));
01330                 if (result != ISC_R_SUCCESS)
01331                         goto cleanup;
01332                 result = dns_peer_setquerydscp(peer, cfg_obj_getdscp(obj));
01333                 if (result != ISC_R_SUCCESS)
01334                         goto cleanup;
01335                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
01336         }
01337 
01338         *peerp = peer;
01339         return (ISC_R_SUCCESS);
01340 
01341  cleanup:
01342         dns_peer_detach(&peer);
01343         return (result);
01344 }
01345 
01346 static isc_result_t
01347 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
01348         isc_result_t result;
01349         const cfg_obj_t *algorithms;
01350         const cfg_listelt_t *element;
01351         const char *str;
01352         dns_fixedname_t fixed;
01353         dns_name_t *name;
01354         isc_buffer_t b;
01355 
01356         dns_fixedname_init(&fixed);
01357         name = dns_fixedname_name(&fixed);
01358         str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
01359         isc_buffer_constinit(&b, str, strlen(str));
01360         isc_buffer_add(&b, strlen(str));
01361         CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
01362 
01363         algorithms = cfg_tuple_get(disabled, "algorithms");
01364         for (element = cfg_list_first(algorithms);
01365              element != NULL;
01366              element = cfg_list_next(element))
01367         {
01368                 isc_textregion_t r;
01369                 dns_secalg_t alg;
01370 
01371                 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
01372                 r.length = strlen(r.base);
01373 
01374                 result = dns_secalg_fromtext(&alg, &r);
01375                 if (result != ISC_R_SUCCESS) {
01376                         isc_uint8_t ui;
01377                         result = isc_parse_uint8(&ui, r.base, 10);
01378                         alg = ui;
01379                 }
01380                 if (result != ISC_R_SUCCESS) {
01381                         cfg_obj_log(cfg_listelt_value(element),
01382                                     ns_g_lctx, ISC_LOG_ERROR,
01383                                     "invalid algorithm");
01384                         CHECK(result);
01385                 }
01386                 CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
01387         }
01388  cleanup:
01389         return (result);
01390 }
01391 
01392 static isc_result_t
01393 disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
01394         isc_result_t result;
01395         const cfg_obj_t *digests;
01396         const cfg_listelt_t *element;
01397         const char *str;
01398         dns_fixedname_t fixed;
01399         dns_name_t *name;
01400         isc_buffer_t b;
01401 
01402         dns_fixedname_init(&fixed);
01403         name = dns_fixedname_name(&fixed);
01404         str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
01405         isc_buffer_constinit(&b, str, strlen(str));
01406         isc_buffer_add(&b, strlen(str));
01407         CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
01408 
01409         digests = cfg_tuple_get(disabled, "digests");
01410         for (element = cfg_list_first(digests);
01411              element != NULL;
01412              element = cfg_list_next(element))
01413         {
01414                 isc_textregion_t r;
01415                 dns_dsdigest_t digest;
01416 
01417                 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
01418                 r.length = strlen(r.base);
01419 
01420                 /* disable_ds_digests handles numeric values. */
01421                 result = dns_dsdigest_fromtext(&digest, &r);
01422                 if (result != ISC_R_SUCCESS) {
01423                         cfg_obj_log(cfg_listelt_value(element),
01424                                     ns_g_lctx, ISC_LOG_ERROR,
01425                                     "invalid algorithm");
01426                         CHECK(result);
01427                 }
01428                 CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
01429         }
01430  cleanup:
01431         return (result);
01432 }
01433 
01434 static isc_boolean_t
01435 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
01436         const cfg_listelt_t *element;
01437         dns_fixedname_t fixed;
01438         dns_name_t *name;
01439         isc_result_t result;
01440         const cfg_obj_t *value;
01441         const char *str;
01442         isc_buffer_t b;
01443 
01444         dns_fixedname_init(&fixed);
01445         name = dns_fixedname_name(&fixed);
01446 
01447         for (element = cfg_list_first(disablelist);
01448              element != NULL;
01449              element = cfg_list_next(element))
01450         {
01451                 value = cfg_listelt_value(element);
01452                 str = cfg_obj_asstring(value);
01453                 isc_buffer_constinit(&b, str, strlen(str));
01454                 isc_buffer_add(&b, strlen(str));
01455                 result = dns_name_fromtext(name, &b, dns_rootname,
01456                                            0, NULL);
01457                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
01458                 if (dns_name_equal(name, zonename))
01459                         return (ISC_TRUE);
01460         }
01461         return (ISC_FALSE);
01462 }
01463 
01464 static isc_result_t
01465 check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
01466              isc_mem_t *mctx)
01467 {
01468         char **argv = NULL;
01469         unsigned int i;
01470         isc_result_t result = ISC_R_SUCCESS;
01471 
01472         CHECK(dns_zone_getdbtype(zone, &argv, mctx));
01473 
01474         /*
01475          * Check that all the arguments match.
01476          */
01477         for (i = 0; i < dbtypec; i++)
01478                 if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0)
01479                         CHECK(ISC_R_FAILURE);
01480 
01481         /*
01482          * Check that there are not extra arguments.
01483          */
01484         if (i == dbtypec && argv[i] != NULL)
01485                 result = ISC_R_FAILURE;
01486 
01487  cleanup:
01488         isc_mem_free(mctx, argv);
01489         return (result);
01490 }
01491 
01492 static isc_result_t
01493 setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
01494         isc_result_t result;
01495         isc_stats_t *zoneqrystats;
01496 
01497         dns_zone_setstatlevel(zone, level);
01498 
01499         zoneqrystats = NULL;
01500         if (level == dns_zonestat_full) {
01501                 result = isc_stats_create(mctx, &zoneqrystats,
01502                                           dns_nsstatscounter_max);
01503                 if (result != ISC_R_SUCCESS)
01504                         return (result);
01505         }
01506         dns_zone_setrequeststats(zone, zoneqrystats);
01507         if (zoneqrystats != NULL)
01508                 isc_stats_detach(&zoneqrystats);
01509 
01510         return (ISC_R_SUCCESS);
01511 }
01512 
01513 static ns_cache_t *
01514 cachelist_find(ns_cachelist_t *cachelist, const char *cachename) {
01515         ns_cache_t *nsc;
01516 
01517         for (nsc = ISC_LIST_HEAD(*cachelist);
01518              nsc != NULL;
01519              nsc = ISC_LIST_NEXT(nsc, link)) {
01520                 if (strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
01521                         return (nsc);
01522         }
01523 
01524         return (NULL);
01525 }
01526 
01527 static isc_boolean_t
01528 cache_reusable(dns_view_t *originview, dns_view_t *view,
01529                isc_boolean_t new_zero_no_soattl)
01530 {
01531         if (originview->checknames != view->checknames ||
01532             dns_resolver_getzeronosoattl(originview->resolver) !=
01533             new_zero_no_soattl ||
01534             originview->acceptexpired != view->acceptexpired ||
01535             originview->enablevalidation != view->enablevalidation ||
01536             originview->maxcachettl != view->maxcachettl ||
01537             originview->maxncachettl != view->maxncachettl) {
01538                 return (ISC_FALSE);
01539         }
01540 
01541         return (ISC_TRUE);
01542 }
01543 
01544 static isc_boolean_t
01545 cache_sharable(dns_view_t *originview, dns_view_t *view,
01546                isc_boolean_t new_zero_no_soattl,
01547                unsigned int new_cleaning_interval,
01548                isc_uint64_t new_max_cache_size)
01549 {
01550         /*
01551          * If the cache cannot even reused for the same view, it cannot be
01552          * shared with other views.
01553          */
01554         if (!cache_reusable(originview, view, new_zero_no_soattl))
01555                 return (ISC_FALSE);
01556 
01557         /*
01558          * Check other cache related parameters that must be consistent among
01559          * the sharing views.
01560          */
01561         if (dns_cache_getcleaninginterval(originview->cache) !=
01562             new_cleaning_interval ||
01563             dns_cache_getcachesize(originview->cache) != new_max_cache_size) {
01564                 return (ISC_FALSE);
01565         }
01566 
01567         return (ISC_TRUE);
01568 }
01569 
01570 /*
01571  * Callback from DLZ configure when the driver sets up a writeable zone
01572  */
01573 static isc_result_t
01574 dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
01575         dns_name_t *origin = dns_zone_getorigin(zone);
01576         dns_rdataclass_t zclass = view->rdclass;
01577         isc_result_t result;
01578 
01579         result = dns_zonemgr_managezone(ns_g_server->zonemgr, zone);
01580         if (result != ISC_R_SUCCESS)
01581                 return (result);
01582         dns_zone_setstats(zone, ns_g_server->zonestats);
01583 
01584         return (ns_zone_configure_writeable_dlz(dlzdb, zone, zclass, origin));
01585 }
01586 
01587 static isc_result_t
01588 dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
01589               unsigned int prefixlen, const char *server,
01590               const char *contact)
01591 {
01592         char *cp;
01593         char reverse[48+sizeof("ip6.arpa.")];
01594         const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
01595         const char *sep = ": view ";
01596         const char *viewname = view->name;
01597         const unsigned char *s6;
01598         dns_fixedname_t fixed;
01599         dns_name_t *name;
01600         dns_zone_t *zone = NULL;
01601         int dns64_dbtypec = 4;
01602         isc_buffer_t b;
01603         isc_result_t result;
01604 
01605         REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
01606                 prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
01607 
01608         if (!strcmp(viewname, "_default")) {
01609                 sep = "";
01610                 viewname = "";
01611         }
01612 
01613         /*
01614          * Construct the reverse name of the zone.
01615          */
01616         cp = reverse;
01617         s6 = na->type.in6.s6_addr;
01618         while (prefixlen > 0) {
01619                 prefixlen -= 8;
01620                 sprintf(cp, "%x.%x.", s6[prefixlen/8] & 0xf,
01621                         (s6[prefixlen/8] >> 4) & 0xf);
01622                 cp += 4;
01623         }
01624         strcat(cp, "ip6.arpa.");
01625 
01626         /*
01627          * Create the actual zone.
01628          */
01629         if (server != NULL)
01630                 dns64_dbtype[2] = server;
01631         if (contact != NULL)
01632                 dns64_dbtype[3] = contact;
01633         dns_fixedname_init(&fixed);
01634         name = dns_fixedname_name(&fixed);
01635         isc_buffer_constinit(&b, reverse, strlen(reverse));
01636         isc_buffer_add(&b, strlen(reverse));
01637         CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
01638         CHECK(dns_zone_create(&zone, mctx));
01639         CHECK(dns_zone_setorigin(zone, name));
01640         dns_zone_setview(zone, view);
01641         CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
01642         dns_zone_setclass(zone, view->rdclass);
01643         dns_zone_settype(zone, dns_zone_master);
01644         dns_zone_setstats(zone, ns_g_server->zonestats);
01645         CHECK(dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype));
01646         if (view->queryacl != NULL)
01647                 dns_zone_setqueryacl(zone, view->queryacl);
01648         if (view->queryonacl != NULL)
01649                 dns_zone_setqueryonacl(zone, view->queryonacl);
01650         dns_zone_setdialup(zone, dns_dialuptype_no);
01651         dns_zone_setnotifytype(zone, dns_notifytype_no);
01652         dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
01653         CHECK(setquerystats(zone, mctx, dns_zonestat_none));    /* XXXMPA */
01654         CHECK(dns_view_addzone(view, zone));
01655         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
01656                       ISC_LOG_INFO, "dns64 reverse zone%s%s: %s", sep,
01657                       viewname, reverse);
01658 
01659 cleanup:
01660         if (zone != NULL)
01661                 dns_zone_detach(&zone);
01662         return (result);
01663 }
01664 
01665 static isc_result_t
01666 configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
01667                    const char *str, const char *msg)
01668 {
01669         isc_result_t result;
01670 
01671         result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx);
01672         if (result != ISC_R_SUCCESS)
01673                 cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01674                             "invalid %s '%s'", msg, str);
01675         return (result);
01676 }
01677 
01678 static isc_result_t
01679 configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
01680                     const char *str, const dns_name_t *origin)
01681 {
01682         isc_result_t result;
01683 
01684         result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE,
01685                                       view->mctx);
01686         if (result != ISC_R_SUCCESS)
01687                 cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01688                             "invalid zone '%s'", str);
01689         return (result);
01690 }
01691 
01692 static isc_result_t
01693 configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
01694                    isc_boolean_t recursive_only_def, dns_ttl_t ttl_def,
01695                    const dns_rpz_zone_t *old, isc_boolean_t *old_rpz_okp)
01696 {
01697         const cfg_obj_t *rpz_obj, *obj;
01698         const char *str;
01699         dns_rpz_zone_t *new;
01700         isc_result_t result;
01701         dns_rpz_num_t rpz_num;
01702 
01703         REQUIRE(old != NULL || !*old_rpz_okp);
01704 
01705         rpz_obj = cfg_listelt_value(element);
01706 
01707         if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
01708                 cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01709                             "limit of %d response policy zones exceeded",
01710                             DNS_RPZ_MAX_ZONES);
01711                 return (ISC_R_FAILURE);
01712         }
01713 
01714         new = isc_mem_get(view->rpzs->mctx, sizeof(*new));
01715         if (new == NULL) {
01716                 cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01717                             "no memory for response policy zones");
01718                 return (ISC_R_NOMEMORY);
01719         }
01720 
01721         memset(new, 0, sizeof(*new));
01722         result = isc_refcount_init(&new->refs, 1);
01723         if (result != ISC_R_SUCCESS) {
01724                 isc_mem_put(view->rpzs->mctx, new, sizeof(*new));
01725                 return (result);
01726         }
01727         dns_name_init(&new->origin, NULL);
01728         dns_name_init(&new->client_ip, NULL);
01729         dns_name_init(&new->ip, NULL);
01730         dns_name_init(&new->nsdname, NULL);
01731         dns_name_init(&new->nsip, NULL);
01732         dns_name_init(&new->passthru, NULL);
01733         dns_name_init(&new->drop, NULL);
01734         dns_name_init(&new->tcp_only, NULL);
01735         dns_name_init(&new->cname, NULL);
01736         new->num = view->rpzs->p.num_zones++;
01737         view->rpzs->zones[new->num] = new;
01738 
01739         obj = cfg_tuple_get(rpz_obj, "recursive-only");
01740         if (cfg_obj_isvoid(obj) ? recursive_only_def : cfg_obj_asboolean(obj)) {
01741                 view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(new->num);
01742         } else {
01743                 view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(new->num);
01744         }
01745 
01746         obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
01747         if (cfg_obj_isuint32(obj)) {
01748                 new->max_policy_ttl = cfg_obj_asuint32(obj);
01749         } else {
01750                 new->max_policy_ttl = ttl_def;
01751         }
01752         if (*old_rpz_okp && new->max_policy_ttl != old->max_policy_ttl)
01753                 *old_rpz_okp = ISC_FALSE;
01754 
01755         str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
01756         result = configure_rpz_name(view, rpz_obj, &new->origin, str, "zone");
01757         if (result != ISC_R_SUCCESS)
01758                 return (result);
01759         if (dns_name_equal(&new->origin, dns_rootname)) {
01760                 cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01761                             "invalid zone name '%s'", str);
01762                 return (DNS_R_EMPTYLABEL);
01763         }
01764         for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones-1; ++rpz_num) {
01765                 if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
01766                                    &new->origin)) {
01767                         cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01768                                     "duplicate '%s'", str);
01769                         result = DNS_R_DUPLICATE;
01770                         return (result);
01771                 }
01772         }
01773         if (*old_rpz_okp && !dns_name_equal(&old->origin, &new->origin))
01774                 *old_rpz_okp = ISC_FALSE;
01775 
01776         result = configure_rpz_name2(view, rpz_obj, &new->client_ip,
01777                                      DNS_RPZ_CLIENT_IP_ZONE, &new->origin);
01778         if (result != ISC_R_SUCCESS)
01779                 return (result);
01780 
01781         result = configure_rpz_name2(view, rpz_obj, &new->ip,
01782                                      DNS_RPZ_IP_ZONE, &new->origin);
01783         if (result != ISC_R_SUCCESS)
01784                 return (result);
01785 
01786         result = configure_rpz_name2(view, rpz_obj, &new->nsdname,
01787                                      DNS_RPZ_NSDNAME_ZONE, &new->origin);
01788         if (result != ISC_R_SUCCESS)
01789                 return (result);
01790 
01791         result = configure_rpz_name2(view, rpz_obj, &new->nsip,
01792                                      DNS_RPZ_NSIP_ZONE, &new->origin);
01793         if (result != ISC_R_SUCCESS)
01794                 return (result);
01795 
01796         result = configure_rpz_name(view, rpz_obj, &new->passthru,
01797                                     DNS_RPZ_PASSTHRU_NAME, "name");
01798         if (result != ISC_R_SUCCESS)
01799                 return (result);
01800 
01801         result = configure_rpz_name(view, rpz_obj, &new->drop,
01802                                     DNS_RPZ_DROP_NAME, "name");
01803         if (result != ISC_R_SUCCESS)
01804                 return (result);
01805 
01806         result = configure_rpz_name(view, rpz_obj, &new->tcp_only,
01807                                     DNS_RPZ_TCP_ONLY_NAME, "name");
01808         if (result != ISC_R_SUCCESS)
01809                 return (result);
01810 
01811         obj = cfg_tuple_get(rpz_obj, "policy");
01812         if (cfg_obj_isvoid(obj)) {
01813                 new->policy = DNS_RPZ_POLICY_GIVEN;
01814         } else {
01815                 str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
01816                 new->policy = dns_rpz_str2policy(str);
01817                 INSIST(new->policy != DNS_RPZ_POLICY_ERROR);
01818                 if (new->policy == DNS_RPZ_POLICY_CNAME) {
01819                         str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
01820                         result = configure_rpz_name(view, rpz_obj, &new->cname,
01821                                                     str, "cname");
01822                         if (result != ISC_R_SUCCESS)
01823                                 return (result);
01824                 }
01825         }
01826         if (*old_rpz_okp && (new->policy != old->policy ||
01827                              !dns_name_equal(&old->cname, &new->cname)))
01828                 *old_rpz_okp = ISC_FALSE;
01829 
01830         return (ISC_R_SUCCESS);
01831 }
01832 
01833 static isc_result_t
01834 configure_rpz(dns_view_t *view, const cfg_obj_t *rpz_obj,
01835               isc_boolean_t *old_rpz_okp)
01836 {
01837         const cfg_listelt_t *zone_element;
01838         const cfg_obj_t *sub_obj;
01839         isc_boolean_t recursive_only_def;
01840         dns_ttl_t ttl_def;
01841         dns_rpz_zones_t *new;
01842         const dns_rpz_zones_t *old;
01843         dns_view_t *pview;
01844         const dns_rpz_zone_t *old_zone;
01845         isc_result_t result;
01846         int i;
01847 
01848         *old_rpz_okp = ISC_FALSE;
01849 
01850         zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
01851         if (zone_element == NULL)
01852                 return (ISC_R_SUCCESS);
01853 
01854         result = dns_rpz_new_zones(&view->rpzs, view->mctx);
01855         if (result != ISC_R_SUCCESS)
01856                 return (result);
01857         new = view->rpzs;
01858 
01859         sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
01860         if (!cfg_obj_isvoid(sub_obj) &&
01861             !cfg_obj_asboolean(sub_obj))
01862                 recursive_only_def = ISC_FALSE;
01863         else
01864                 recursive_only_def = ISC_TRUE;
01865 
01866         sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
01867         if (!cfg_obj_isvoid(sub_obj) &&
01868             cfg_obj_asboolean(sub_obj))
01869                 new->p.break_dnssec = ISC_TRUE;
01870         else
01871                 new->p.break_dnssec = ISC_FALSE;
01872 
01873         sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
01874         if (cfg_obj_isuint32(sub_obj))
01875                 ttl_def = cfg_obj_asuint32(sub_obj);
01876         else
01877                 ttl_def = DNS_RPZ_MAX_TTL_DEFAULT;
01878 
01879         sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
01880         if (cfg_obj_isuint32(sub_obj))
01881                 new->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
01882         else
01883                 new->p.min_ns_labels = 2;
01884 
01885         sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
01886         if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj))
01887                 new->p.qname_wait_recurse = ISC_TRUE;
01888         else
01889                 new->p.qname_wait_recurse = ISC_FALSE;
01890 
01891         pview = NULL;
01892         result = dns_viewlist_find(&ns_g_server->viewlist,
01893                                    view->name, view->rdclass, &pview);
01894         if (result == ISC_R_SUCCESS) {
01895                 old = pview->rpzs;
01896         } else {
01897                 old = NULL;
01898         }
01899         if (old == NULL)
01900                 *old_rpz_okp = ISC_FALSE;
01901         else
01902                 *old_rpz_okp = ISC_TRUE;
01903 
01904         for (i = 0;
01905              zone_element != NULL;
01906              ++i, zone_element = cfg_list_next(zone_element)) {
01907                 INSIST(old != NULL || !*old_rpz_okp);
01908                 if (*old_rpz_okp && i < old->p.num_zones) {
01909                         old_zone = old->zones[i];
01910                 } else {
01911                         *old_rpz_okp = ISC_FALSE;
01912                         old_zone = NULL;
01913                 }
01914                 result = configure_rpz_zone(view, zone_element,
01915                                             recursive_only_def, ttl_def,
01916                                             old_zone, old_rpz_okp);
01917                 if (result != ISC_R_SUCCESS) {
01918                         if (pview != NULL)
01919                                 dns_view_detach(&pview);
01920                         return (result);
01921                 }
01922         }
01923 
01924         /*
01925          * If this is a reloading and the parameters and list of policy
01926          * zones are unchanged, then use the same policy data.
01927          * Data for individual zones that must be reloaded will be merged.
01928          */
01929         if (old != NULL && memcmp(&old->p, &new->p, sizeof(new->p)) != 0)
01930                 *old_rpz_okp = ISC_FALSE;
01931         if (*old_rpz_okp) {
01932                 dns_rpz_detach_rpzs(&view->rpzs);
01933                 dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
01934         }
01935         if (pview != NULL)
01936                 dns_view_detach(&pview);
01937 
01938         return (ISC_R_SUCCESS);
01939 }
01940 
01941 #define CHECK_RRL(cond, pat, val1, val2)                                \
01942         do {                                                            \
01943                 if (!(cond)) {                                          \
01944                         cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,      \
01945                                     pat, val1, val2);                   \
01946                         result = ISC_R_RANGE;                           \
01947                         goto cleanup;                                   \
01948                     }                                                   \
01949         } while (0)
01950 
01951 #define CHECK_RRL_RATE(rate, def, max_rate, name)                       \
01952         do {                                                            \
01953                 obj = NULL;                                             \
01954                 rrl->rate.str = name;                                   \
01955                 result = cfg_map_get(map, name, &obj);                  \
01956                 if (result == ISC_R_SUCCESS) {                          \
01957                         rrl->rate.r = cfg_obj_asuint32(obj);            \
01958                         CHECK_RRL(rrl->rate.r <= max_rate,              \
01959                                   name" %d > %d",                       \
01960                                   rrl->rate.r, max_rate);               \
01961                 } else {                                                \
01962                         rrl->rate.r = def;                              \
01963                 }                                                       \
01964                 rrl->rate.scaled = rrl->rate.r;                         \
01965         } while (0)
01966 
01967 static isc_result_t
01968 configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
01969         const cfg_obj_t *obj;
01970         dns_rrl_t *rrl;
01971         isc_result_t result;
01972         int min_entries, i, j;
01973 
01974         /*
01975          * Most DNS servers have few clients, but intentinally open
01976          * recursive and authoritative servers often have many.
01977          * So start with a small number of entries unless told otherwise
01978          * to reduce cold-start costs.
01979          */
01980         min_entries = 500;
01981         obj = NULL;
01982         result = cfg_map_get(map, "min-table-size", &obj);
01983         if (result == ISC_R_SUCCESS) {
01984                 min_entries = cfg_obj_asuint32(obj);
01985                 if (min_entries < 1)
01986                         min_entries = 1;
01987         }
01988         result = dns_rrl_init(&rrl, view, min_entries);
01989         if (result != ISC_R_SUCCESS)
01990                 return (result);
01991 
01992         i = ISC_MAX(20000, min_entries);
01993         obj = NULL;
01994         result = cfg_map_get(map, "max-table-size", &obj);
01995         if (result == ISC_R_SUCCESS) {
01996                 i = cfg_obj_asuint32(obj);
01997                 CHECK_RRL(i >= min_entries,
01998                           "max-table-size %d < min-table-size %d",
01999                           i, min_entries);
02000         }
02001         rrl->max_entries = i;
02002 
02003         CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
02004                        "responses-per-second");
02005         CHECK_RRL_RATE(referrals_per_second,
02006                        rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
02007                        "referrals-per-second");
02008         CHECK_RRL_RATE(nodata_per_second,
02009                        rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
02010                        "nodata-per-second");
02011         CHECK_RRL_RATE(nxdomains_per_second,
02012                        rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
02013                        "nxdomains-per-second");
02014         CHECK_RRL_RATE(errors_per_second,
02015                        rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
02016                        "errors-per-second");
02017 
02018         CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE,
02019                        "all-per-second");
02020 
02021         CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP,
02022                        "slip");
02023 
02024         i = 15;
02025         obj = NULL;
02026         result = cfg_map_get(map, "window", &obj);
02027         if (result == ISC_R_SUCCESS) {
02028                 i = cfg_obj_asuint32(obj);
02029                 CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
02030                           "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
02031         }
02032         rrl->window = i;
02033 
02034         i = 0;
02035         obj = NULL;
02036         result = cfg_map_get(map, "qps-scale", &obj);
02037         if (result == ISC_R_SUCCESS) {
02038                 i = cfg_obj_asuint32(obj);
02039                 CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
02040         }
02041         rrl->qps_scale = i;
02042         rrl->qps = 1.0;
02043 
02044         i = 24;
02045         obj = NULL;
02046         result = cfg_map_get(map, "ipv4-prefix-length", &obj);
02047         if (result == ISC_R_SUCCESS) {
02048                 i = cfg_obj_asuint32(obj);
02049                 CHECK_RRL(i >= 8 && i <= 32,
02050                           "invalid 'ipv4-prefix-length %d'%s", i, "");
02051         }
02052         rrl->ipv4_prefixlen = i;
02053         if (i == 32)
02054                 rrl->ipv4_mask = 0xffffffff;
02055         else
02056                 rrl->ipv4_mask = htonl(0xffffffff << (32-i));
02057 
02058         i = 56;
02059         obj = NULL;
02060         result = cfg_map_get(map, "ipv6-prefix-length", &obj);
02061         if (result == ISC_R_SUCCESS) {
02062                 i = cfg_obj_asuint32(obj);
02063                 CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
02064                           "ipv6-prefix-length %d < 16 or > %d",
02065                           i, DNS_RRL_MAX_PREFIX);
02066         }
02067         rrl->ipv6_prefixlen = i;
02068         for (j = 0; j < 4; ++j) {
02069                 if (i <= 0) {
02070                         rrl->ipv6_mask[j] = 0;
02071                 } else if (i < 32) {
02072                         rrl->ipv6_mask[j] = htonl(0xffffffff << (32-i));
02073                 } else {
02074                         rrl->ipv6_mask[j] = 0xffffffff;
02075                 }
02076                 i -= 32;
02077         }
02078 
02079         obj = NULL;
02080         result = cfg_map_get(map, "exempt-clients", &obj);
02081         if (result == ISC_R_SUCCESS) {
02082                 result = cfg_acl_fromconfig(obj, config, ns_g_lctx,
02083                                             ns_g_aclconfctx, ns_g_mctx,
02084                                             0, &rrl->exempt);
02085                 CHECK_RRL(result == ISC_R_SUCCESS,
02086                           "invalid %s%s", "address match list", "");
02087         }
02088 
02089         obj = NULL;
02090         result = cfg_map_get(map, "log-only", &obj);
02091         if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj))
02092                 rrl->log_only = ISC_TRUE;
02093         else
02094                 rrl->log_only = ISC_FALSE;
02095 
02096         return (ISC_R_SUCCESS);
02097 
02098  cleanup:
02099         dns_rrl_view_destroy(view);
02100         return (result);
02101 }
02102 
02103 static isc_result_t
02104 add_soa(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
02105         dns_name_t *origin, dns_name_t *contact)
02106 {
02107         dns_dbnode_t *node = NULL;
02108         dns_rdata_t rdata = DNS_RDATA_INIT;
02109         dns_rdatalist_t rdatalist;
02110         dns_rdataset_t rdataset;
02111         isc_result_t result;
02112         unsigned char buf[DNS_SOA_BUFFERSIZE];
02113 
02114         CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db),
02115                                  0, 28800, 7200, 604800, 86400, buf, &rdata));
02116 
02117         dns_rdatalist_init(&rdatalist);
02118         rdatalist.type = rdata.type;
02119         rdatalist.rdclass = rdata.rdclass;
02120         rdatalist.ttl = 86400;
02121         ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
02122 
02123         dns_rdataset_init(&rdataset);
02124         CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
02125         CHECK(dns_db_findnode(db, name, ISC_TRUE, &node));
02126         CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
02127 
02128  cleanup:
02129         if (node != NULL)
02130                 dns_db_detachnode(db, &node);
02131         return (result);
02132 }
02133 
02134 static isc_result_t
02135 add_ns(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
02136        dns_name_t *nsname)
02137 {
02138         dns_dbnode_t *node = NULL;
02139         dns_rdata_ns_t ns;
02140         dns_rdata_t rdata = DNS_RDATA_INIT;
02141         dns_rdatalist_t rdatalist;
02142         dns_rdataset_t rdataset;
02143         isc_result_t result;
02144         isc_buffer_t b;
02145         unsigned char buf[DNS_NAME_MAXWIRE];
02146 
02147         isc_buffer_init(&b, buf, sizeof(buf));
02148 
02149         ns.common.rdtype = dns_rdatatype_ns;
02150         ns.common.rdclass = dns_db_class(db);
02151         ns.mctx = NULL;
02152         dns_name_init(&ns.name, NULL);
02153         dns_name_clone(nsname, &ns.name);
02154         CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
02155                                    &ns, &b));
02156 
02157         dns_rdatalist_init(&rdatalist);
02158         rdatalist.type = rdata.type;
02159         rdatalist.rdclass = rdata.rdclass;
02160         rdatalist.ttl = 86400;
02161         ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
02162 
02163         dns_rdataset_init(&rdataset);
02164         CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
02165         CHECK(dns_db_findnode(db, name, ISC_TRUE, &node));
02166         CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
02167 
02168  cleanup:
02169         if (node != NULL)
02170                 dns_db_detachnode(db, &node);
02171         return (result);
02172 }
02173 
02174 static isc_result_t
02175 create_empty_zone(dns_zone_t *zone, dns_name_t *name, dns_view_t *view,
02176                   const cfg_obj_t *zonelist, const char **empty_dbtype,
02177                   int empty_dbtypec, dns_zonestat_level_t statlevel)
02178 {
02179         char namebuf[DNS_NAME_FORMATSIZE];
02180         const cfg_listelt_t *element;
02181         const cfg_obj_t *obj;
02182         const cfg_obj_t *zconfig;
02183         const cfg_obj_t *zoptions;
02184         const char *rbt_dbtype[4] = { "rbt" };
02185         const char *sep = ": view ";
02186         const char *str;
02187         const char *viewname = view->name;
02188         dns_db_t *db = NULL;
02189         dns_dbversion_t *version = NULL;
02190         dns_fixedname_t cfixed;
02191         dns_fixedname_t fixed;
02192         dns_fixedname_t nsfixed;
02193         dns_name_t *contact;
02194         dns_name_t *ns;
02195         dns_name_t *zname;
02196         dns_zone_t *myzone = NULL;
02197         int rbt_dbtypec = 1;
02198         isc_result_t result;
02199         dns_namereln_t namereln;
02200         int order;
02201         unsigned int nlabels;
02202 
02203         dns_fixedname_init(&fixed);
02204         zname = dns_fixedname_name(&fixed);
02205         dns_fixedname_init(&nsfixed);
02206         ns = dns_fixedname_name(&nsfixed);
02207         dns_fixedname_init(&cfixed);
02208         contact = dns_fixedname_name(&cfixed);
02209 
02210         /*
02211          * Look for forward "zones" beneath this empty zone and if so
02212          * create a custom db for the empty zone.
02213          */
02214         for (element = cfg_list_first(zonelist);
02215              element != NULL;
02216              element = cfg_list_next(element)) {
02217 
02218                 zconfig = cfg_listelt_value(element);
02219                 str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
02220                 CHECK(dns_name_fromstring(zname, str, 0, NULL));
02221                 namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
02222                 if (namereln != dns_namereln_subdomain)
02223                         continue;
02224 
02225                 zoptions = cfg_tuple_get(zconfig, "options");
02226 
02227                 obj = NULL;
02228                 (void)cfg_map_get(zoptions, "type", &obj);
02229                 if (obj != NULL &&
02230                     strcasecmp(cfg_obj_asstring(obj), "forward") == 0) {
02231                         obj = NULL;
02232                         (void)cfg_map_get(zoptions, "forward", &obj);
02233                         if (obj == NULL)
02234                                 continue;
02235                         if (strcasecmp(cfg_obj_asstring(obj), "only") != 0)
02236                                 continue;
02237                 }
02238                 if (db == NULL) {
02239                         CHECK(dns_db_create(view->mctx, "rbt", name,
02240                                             dns_dbtype_zone, view->rdclass,
02241                                             0, NULL, &db));
02242                         CHECK(dns_db_newversion(db, &version));
02243                         if (strcmp(empty_dbtype[2], "@") == 0)
02244                                 dns_name_clone(name, ns);
02245                         else
02246                                 CHECK(dns_name_fromstring(ns, empty_dbtype[2],
02247                                                           0, NULL));
02248                         CHECK(dns_name_fromstring(contact, empty_dbtype[3],
02249                                                   0, NULL));
02250                         CHECK(add_soa(db, version, name, ns, contact));
02251                         CHECK(add_ns(db, version, name, ns));
02252                 }
02253                 CHECK(add_ns(db, version, zname, dns_rootname));
02254         }
02255 
02256         /*
02257          * Is the existing zone the ok to use?
02258          */
02259         if (zone != NULL) {
02260                 unsigned int typec;
02261                 const char **dbargv;
02262 
02263                 if (db != NULL) {
02264                         typec = rbt_dbtypec;
02265                         dbargv = rbt_dbtype;
02266                 } else {
02267                         typec = empty_dbtypec;
02268                         dbargv = empty_dbtype;
02269                 }
02270 
02271                 result = check_dbtype(zone, typec, dbargv, view->mctx);
02272                 if (result != ISC_R_SUCCESS)
02273                         zone = NULL;
02274 
02275                 if (zone != NULL && dns_zone_gettype(zone) != dns_zone_master)
02276                         zone = NULL;
02277                 if (zone != NULL && dns_zone_getfile(zone) != NULL)
02278                         zone = NULL;
02279                 if (zone != NULL) {
02280                         dns_zone_getraw(zone, &myzone);
02281                         if (myzone != NULL) {
02282                                 dns_zone_detach(&myzone);
02283                                 zone = NULL;
02284                         }
02285                 }
02286         }
02287 
02288         if (zone == NULL) {
02289                 CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &myzone));
02290                 zone = myzone;
02291                 CHECK(dns_zone_setorigin(zone, name));
02292                 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
02293                 if (db == NULL)
02294                         CHECK(dns_zone_setdbtype(zone, empty_dbtypec,
02295                                                  empty_dbtype));
02296                 dns_zone_setclass(zone, view->rdclass);
02297                 dns_zone_settype(zone, dns_zone_master);
02298                 dns_zone_setstats(zone, ns_g_server->zonestats);
02299         }
02300 
02301         dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, ISC_FALSE);
02302         dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
02303         dns_zone_setnotifytype(zone, dns_notifytype_no);
02304         dns_zone_setdialup(zone, dns_dialuptype_no);
02305         dns_zone_setautomatic(zone, ISC_TRUE);
02306         if (view->queryacl != NULL)
02307                 dns_zone_setqueryacl(zone, view->queryacl);
02308         else
02309                 dns_zone_clearqueryacl(zone);
02310         if (view->queryonacl != NULL)
02311                 dns_zone_setqueryonacl(zone, view->queryonacl);
02312         else
02313                 dns_zone_clearqueryonacl(zone);
02314         dns_zone_clearupdateacl(zone);
02315         if (view->transferacl != NULL)
02316                 dns_zone_setxfracl(zone, view->transferacl);
02317         else
02318                 dns_zone_clearxfracl(zone);
02319 
02320         CHECK(setquerystats(zone, view->mctx, statlevel));
02321         if (db != NULL) {
02322                 dns_db_closeversion(db, &version, ISC_TRUE);
02323                 CHECK(dns_zone_replacedb(zone, db, ISC_FALSE));
02324         }
02325         dns_zone_setview(zone, view);
02326         CHECK(dns_view_addzone(view, zone));
02327 
02328         if (!strcmp(viewname, "_default")) {
02329                 sep = "";
02330                 viewname = "";
02331         }
02332         dns_name_format(name, namebuf, sizeof(namebuf));
02333         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
02334                       ISC_LOG_INFO, "automatic empty zone%s%s: %s",
02335                       sep, viewname, namebuf);
02336 
02337  cleanup:
02338         if (myzone != NULL)
02339                 dns_zone_detach(&myzone);
02340         if (version != NULL)
02341                 dns_db_closeversion(db, &version, ISC_FALSE);
02342         if (db != NULL)
02343                 dns_db_detach(&db);
02344 
02345         INSIST(version == NULL);
02346 
02347         return (result);
02348 }
02349 
02350 /*
02351  * Configure 'view' according to 'vconfig', taking defaults from 'config'
02352  * where values are missing in 'vconfig'.
02353  *
02354  * When configuring the default view, 'vconfig' will be NULL and the
02355  * global defaults in 'config' used exclusively.
02356  */
02357 static isc_result_t
02358 configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
02359                cfg_obj_t *config, cfg_obj_t *vconfig,
02360                ns_cachelist_t *cachelist, const cfg_obj_t *bindkeys,
02361                isc_mem_t *mctx, cfg_aclconfctx_t *actx,
02362                isc_boolean_t need_hints)
02363 {
02364         const cfg_obj_t *maps[4];
02365         const cfg_obj_t *cfgmaps[3];
02366         const cfg_obj_t *optionmaps[3];
02367         const cfg_obj_t *options = NULL;
02368         const cfg_obj_t *voptions = NULL;
02369         const cfg_obj_t *forwardtype;
02370         const cfg_obj_t *forwarders;
02371         const cfg_obj_t *alternates;
02372         const cfg_obj_t *zonelist;
02373         const cfg_obj_t *dlzlist;
02374         const cfg_obj_t *dlz;
02375         unsigned int dlzargc;
02376         char **dlzargv;
02377         const cfg_obj_t *disabled;
02378         const cfg_obj_t *obj;
02379         const cfg_listelt_t *element;
02380         in_port_t port;
02381         dns_cache_t *cache = NULL;
02382         isc_result_t result;
02383         unsigned int cleaning_interval;
02384         size_t max_cache_size;
02385         size_t max_acache_size;
02386         size_t max_adb_size;
02387         isc_uint32_t lame_ttl, fail_ttl;
02388         dns_tsig_keyring_t *ring = NULL;
02389         dns_view_t *pview = NULL;       /* Production view */
02390         isc_mem_t *cmctx = NULL, *hmctx = NULL;
02391         dns_dispatch_t *dispatch4 = NULL;
02392         dns_dispatch_t *dispatch6 = NULL;
02393         isc_boolean_t reused_cache = ISC_FALSE;
02394         isc_boolean_t shared_cache = ISC_FALSE;
02395         int i = 0, j = 0, k = 0;
02396         const char *str;
02397         const char *cachename = NULL;
02398         dns_order_t *order = NULL;
02399         isc_uint32_t udpsize;
02400         isc_uint32_t maxbits;
02401         unsigned int resopts = 0;
02402         dns_zone_t *zone = NULL;
02403         isc_uint32_t max_clients_per_query;
02404         isc_boolean_t empty_zones_enable;
02405         const cfg_obj_t *disablelist = NULL;
02406         isc_stats_t *resstats = NULL;
02407         dns_stats_t *resquerystats = NULL;
02408         isc_boolean_t auto_dlv = ISC_FALSE;
02409         isc_boolean_t auto_root = ISC_FALSE;
02410         ns_cache_t *nsc;
02411         isc_boolean_t zero_no_soattl;
02412         dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
02413         unsigned int query_timeout, ndisp;
02414         ns_cfgctx_t *nzctx;
02415         isc_boolean_t old_rpz_ok = ISC_FALSE;
02416         isc_dscp_t dscp4 = -1, dscp6 = -1;
02417 
02418         REQUIRE(DNS_VIEW_VALID(view));
02419 
02420         if (config != NULL)
02421                 (void)cfg_map_get(config, "options", &options);
02422 
02423         /*
02424          * maps: view options, options, defaults
02425          * cfgmaps: view options, config
02426          * optionmaps: view options, options
02427          */
02428         if (vconfig != NULL) {
02429                 voptions = cfg_tuple_get(vconfig, "options");
02430                 maps[i++] = voptions;
02431                 optionmaps[j++] = voptions;
02432                 cfgmaps[k++] = voptions;
02433         }
02434         if (options != NULL) {
02435                 maps[i++] = options;
02436                 optionmaps[j++] = options;
02437         }
02438 
02439         maps[i++] = ns_g_defaults;
02440         maps[i] = NULL;
02441         optionmaps[j] = NULL;
02442         if (config != NULL)
02443                 cfgmaps[k++] = config;
02444         cfgmaps[k] = NULL;
02445 
02446         /*
02447          * Set the view's port number for outgoing queries.
02448          */
02449         CHECKM(ns_config_getport(config, &port), "port");
02450         dns_view_setdstport(view, port);
02451 
02452         /*
02453          * Create additional cache for this view and zones under the view
02454          * if explicitly enabled.
02455          * XXX950 default to on.
02456          */
02457         obj = NULL;
02458         (void)ns_config_get(maps, "acache-enable", &obj);
02459         if (obj != NULL && cfg_obj_asboolean(obj)) {
02460                 cmctx = NULL;
02461                 CHECK(isc_mem_create(0, 0, &cmctx));
02462                 CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr,
02463                                         ns_g_timermgr));
02464                 isc_mem_setname(cmctx, "acache", NULL);
02465                 isc_mem_detach(&cmctx);
02466         }
02467         if (view->acache != NULL) {
02468                 obj = NULL;
02469                 result = ns_config_get(maps, "acache-cleaning-interval", &obj);
02470                 INSIST(result == ISC_R_SUCCESS);
02471                 dns_acache_setcleaninginterval(view->acache,
02472                                                cfg_obj_asuint32(obj) * 60);
02473 
02474                 obj = NULL;
02475                 result = ns_config_get(maps, "max-acache-size", &obj);
02476                 INSIST(result == ISC_R_SUCCESS);
02477                 if (cfg_obj_isstring(obj)) {
02478                         str = cfg_obj_asstring(obj);
02479                         INSIST(strcasecmp(str, "unlimited") == 0);
02480                         max_acache_size = 0;
02481                 } else {
02482                         isc_resourcevalue_t value;
02483                         value = cfg_obj_asuint64(obj);
02484                         if (value > SIZE_MAX) {
02485                                 cfg_obj_log(obj, ns_g_lctx,
02486                                             ISC_LOG_WARNING,
02487                                             "'max-acache-size "
02488                                             "%" ISC_PRINT_QUADFORMAT "u' "
02489                                             "is too large for this "
02490                                             "system; reducing to %lu",
02491                                             value, (unsigned long)SIZE_MAX);
02492                                 value = SIZE_MAX;
02493                         }
02494                         max_acache_size = (size_t) value;
02495                 }
02496                 dns_acache_setcachesize(view->acache, max_acache_size);
02497         }
02498 
02499         CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx,
02500                                  ns_g_mctx, &view->queryacl));
02501         if (view->queryacl == NULL) {
02502                 CHECK(configure_view_acl(NULL, ns_g_config, "allow-query",
02503                                          NULL, actx, ns_g_mctx,
02504                                          &view->queryacl));
02505         }
02506 
02507         /*
02508          * Make the list of response policy zone names for a view that
02509          * is used for real lookups and so cares about hints.
02510          */
02511         obj = NULL;
02512         if (view->rdclass == dns_rdataclass_in && need_hints &&
02513             ns_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS) {
02514                 CHECK(configure_rpz(view, obj, &old_rpz_ok));
02515         }
02516 
02517         /*
02518          * Configure the zones.
02519          */
02520         zonelist = NULL;
02521         if (voptions != NULL)
02522                 (void)cfg_map_get(voptions, "zone", &zonelist);
02523         else
02524                 (void)cfg_map_get(config, "zone", &zonelist);
02525 
02526         /*
02527          * Load zone configuration
02528          */
02529         for (element = cfg_list_first(zonelist);
02530              element != NULL;
02531              element = cfg_list_next(element))
02532         {
02533                 const cfg_obj_t *zconfig = cfg_listelt_value(element);
02534                 CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
02535                                      viewlist, actx, ISC_FALSE, old_rpz_ok,
02536                                      ISC_FALSE));
02537         }
02538 
02539         /*
02540          * Check that a master or slave zone was found for each
02541          * zone named in the response policy statement.
02542          */
02543         if (view->rpzs != NULL) {
02544                 dns_rpz_num_t n;
02545 
02546                 for (n = 0; n < view->rpzs->p.num_zones; ++n)
02547                 {
02548                         if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
02549                                 char namebuf[DNS_NAME_FORMATSIZE];
02550 
02551                                 dns_name_format(&view->rpzs->zones[n]->origin,
02552                                                 namebuf, sizeof(namebuf));
02553                                 cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
02554                                             "'%s' is not a master or slave zone",
02555                                             namebuf);
02556                                 result = ISC_R_NOTFOUND;
02557                                 goto cleanup;
02558                         }
02559                 }
02560         }
02561 
02562         /*
02563          * If we're allowing added zones, then load zone configuration
02564          * from the newzone file for zones that were added during previous
02565          * runs.
02566          */
02567         nzctx = view->new_zone_config;
02568         if (nzctx != NULL && nzctx->nzconfig != NULL) {
02569                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
02570                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
02571                               "loading additional zones for view '%s'",
02572                               view->name);
02573 
02574                 zonelist = NULL;
02575                 cfg_map_get(nzctx->nzconfig, "zone", &zonelist);
02576 
02577                 for (element = cfg_list_first(zonelist);
02578                      element != NULL;
02579                      element = cfg_list_next(element))
02580                 {
02581                         const cfg_obj_t *zconfig = cfg_listelt_value(element);
02582                         CHECK(configure_zone(config, zconfig, vconfig,
02583                                              mctx, view, NULL, actx,
02584                                              ISC_TRUE, ISC_FALSE, ISC_FALSE));
02585                 }
02586         }
02587 
02588         /*
02589          * Create Dynamically Loadable Zone driver.
02590          */
02591         dlzlist = NULL;
02592         if (voptions != NULL)
02593                 (void)cfg_map_get(voptions, "dlz", &dlzlist);
02594         else
02595                 (void)cfg_map_get(config, "dlz", &dlzlist);
02596 
02597         for (element = cfg_list_first(dlzlist);
02598              element != NULL;
02599              element = cfg_list_next(element))
02600         {
02601                 dlz = cfg_listelt_value(element);
02602 
02603                 obj = NULL;
02604                 (void)cfg_map_get(dlz, "database", &obj);
02605                 if (obj != NULL) {
02606                         dns_dlzdb_t *dlzdb = NULL;
02607                         const cfg_obj_t *name, *search = NULL;
02608                         char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
02609 
02610                         if (s == NULL) {
02611                                 result = ISC_R_NOMEMORY;
02612                                 goto cleanup;
02613                         }
02614 
02615                         result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv);
02616                         if (result != ISC_R_SUCCESS) {
02617                                 isc_mem_free(mctx, s);
02618                                 goto cleanup;
02619                         }
02620 
02621                         name = cfg_map_getname(dlz);
02622                         result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
02623                                                dlzargv[0], dlzargc, dlzargv,
02624                                                &dlzdb);
02625                         isc_mem_free(mctx, s);
02626                         isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
02627                         if (result != ISC_R_SUCCESS)
02628                                 goto cleanup;
02629 
02630                         /*
02631                          * If the DLZ backend supports configuration,
02632                          * and is searchable, then call its configure
02633                          * method now.  If not searchable, we'll take
02634                          * care of it when we process the zone statement.
02635                          */
02636                         (void)cfg_map_get(dlz, "search", &search);
02637                         if (search == NULL || cfg_obj_asboolean(search)) {
02638                                 dlzdb->search = ISC_TRUE;
02639                                 result = dns_dlzconfigure(view, dlzdb,
02640                                                         dlzconfigure_callback);
02641                                 if (result != ISC_R_SUCCESS)
02642                                         goto cleanup;
02643                                 ISC_LIST_APPEND(view->dlz_searched,
02644                                                 dlzdb, link);
02645                         } else {
02646                                 dlzdb->search = ISC_FALSE;
02647                                 ISC_LIST_APPEND(view->dlz_unsearched,
02648                                                 dlzdb, link);
02649                         }
02650 
02651                 }
02652         }
02653 
02654         /*
02655          * Obtain configuration parameters that affect the decision of whether
02656          * we can reuse/share an existing cache.
02657          */
02658         obj = NULL;
02659         result = ns_config_get(maps, "cleaning-interval", &obj);
02660         INSIST(result == ISC_R_SUCCESS);
02661         cleaning_interval = cfg_obj_asuint32(obj) * 60;
02662 
02663         obj = NULL;
02664         result = ns_config_get(maps, "max-cache-size", &obj);
02665         INSIST(result == ISC_R_SUCCESS);
02666         if (cfg_obj_isstring(obj)) {
02667                 str = cfg_obj_asstring(obj);
02668                 INSIST(strcasecmp(str, "unlimited") == 0);
02669                 max_cache_size = 0;
02670         } else {
02671                 isc_resourcevalue_t value;
02672                 value = cfg_obj_asuint64(obj);
02673                 if (value > SIZE_MAX) {
02674                         cfg_obj_log(obj, ns_g_lctx,
02675                                     ISC_LOG_WARNING,
02676                                     "'max-cache-size "
02677                                     "%" ISC_PRINT_QUADFORMAT "u' "
02678                                     "is too large for this "
02679                                     "system; reducing to %lu",
02680                                     value, (unsigned long)SIZE_MAX);
02681                         value = SIZE_MAX;
02682                 }
02683                 max_cache_size = (size_t) value;
02684         }
02685 
02686         /* Check-names. */
02687         obj = NULL;
02688         result = ns_checknames_get(maps, "response", &obj);
02689         INSIST(result == ISC_R_SUCCESS);
02690 
02691         str = cfg_obj_asstring(obj);
02692         if (strcasecmp(str, "fail") == 0) {
02693                 resopts |= DNS_RESOLVER_CHECKNAMES |
02694                         DNS_RESOLVER_CHECKNAMESFAIL;
02695                 view->checknames = ISC_TRUE;
02696         } else if (strcasecmp(str, "warn") == 0) {
02697                 resopts |= DNS_RESOLVER_CHECKNAMES;
02698                 view->checknames = ISC_FALSE;
02699         } else if (strcasecmp(str, "ignore") == 0) {
02700                 view->checknames = ISC_FALSE;
02701         } else
02702                 INSIST(0);
02703 
02704         obj = NULL;
02705         result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj);
02706         INSIST(result == ISC_R_SUCCESS);
02707         zero_no_soattl = cfg_obj_asboolean(obj);
02708 
02709         obj = NULL;
02710         result = ns_config_get(maps, "dns64", &obj);
02711         if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
02712             strcmp(view->name, "_meta")) {
02713                 isc_netaddr_t na, suffix, *sp;
02714                 unsigned int prefixlen;
02715                 const char *server, *contact;
02716                 const cfg_obj_t *myobj;
02717 
02718                 myobj = NULL;
02719                 result = ns_config_get(maps, "dns64-server", &myobj);
02720                 if (result == ISC_R_SUCCESS)
02721                         server = cfg_obj_asstring(myobj);
02722                 else
02723                         server = NULL;
02724 
02725                 myobj = NULL;
02726                 result = ns_config_get(maps, "dns64-contact", &myobj);
02727                 if (result == ISC_R_SUCCESS)
02728                         contact = cfg_obj_asstring(myobj);
02729                 else
02730                         contact = NULL;
02731 
02732                 for (element = cfg_list_first(obj);
02733                      element != NULL;
02734                      element = cfg_list_next(element))
02735                 {
02736                         const cfg_obj_t *map = cfg_listelt_value(element);
02737                         dns_dns64_t *dns64 = NULL;
02738                         unsigned int dns64options = 0;
02739 
02740                         cfg_obj_asnetprefix(cfg_map_getname(map), &na,
02741                                             &prefixlen);
02742 
02743                         obj = NULL;
02744                         (void)cfg_map_get(map, "suffix", &obj);
02745                         if (obj != NULL) {
02746                                 sp = &suffix;
02747                                 isc_netaddr_fromsockaddr(sp,
02748                                                       cfg_obj_assockaddr(obj));
02749                         } else
02750                                 sp = NULL;
02751 
02752                         clients = mapped = excluded = NULL;
02753                         obj = NULL;
02754                         (void)cfg_map_get(map, "clients", &obj);
02755                         if (obj != NULL) {
02756                                 result = cfg_acl_fromconfig(obj, config,
02757                                                             ns_g_lctx, actx,
02758                                                             mctx, 0, &clients);
02759                                 if (result != ISC_R_SUCCESS)
02760                                         goto cleanup;
02761                         }
02762                         obj = NULL;
02763                         (void)cfg_map_get(map, "mapped", &obj);
02764                         if (obj != NULL) {
02765                                 result = cfg_acl_fromconfig(obj, config,
02766                                                             ns_g_lctx, actx,
02767                                                             mctx, 0, &mapped);
02768                                 if (result != ISC_R_SUCCESS)
02769                                         goto cleanup;
02770                         }
02771                         obj = NULL;
02772                         (void)cfg_map_get(map, "exclude", &obj);
02773                         if (obj != NULL) {
02774                                 result = cfg_acl_fromconfig(obj, config,
02775                                                             ns_g_lctx, actx,
02776                                                             mctx, 0, &excluded);
02777                                 if (result != ISC_R_SUCCESS)
02778                                         goto cleanup;
02779                         }
02780 
02781                         obj = NULL;
02782                         (void)cfg_map_get(map, "recursive-only", &obj);
02783                         if (obj != NULL && cfg_obj_asboolean(obj))
02784                                 dns64options |= DNS_DNS64_RECURSIVE_ONLY;
02785 
02786                         obj = NULL;
02787                         (void)cfg_map_get(map, "break-dnssec", &obj);
02788                         if (obj != NULL && cfg_obj_asboolean(obj))
02789                                 dns64options |= DNS_DNS64_BREAK_DNSSEC;
02790 
02791                         result = dns_dns64_create(mctx, &na, prefixlen, sp,
02792                                                   clients, mapped, excluded,
02793                                                   dns64options, &dns64);
02794                         if (result != ISC_R_SUCCESS)
02795                                 goto cleanup;
02796                         dns_dns64_append(&view->dns64, dns64);
02797                         view->dns64cnt++;
02798                         result = dns64_reverse(view, mctx, &na, prefixlen,
02799                                                server, contact);
02800                         if (result != ISC_R_SUCCESS)
02801                                 goto cleanup;
02802                         if (clients != NULL)
02803                                 dns_acl_detach(&clients);
02804                         if (mapped != NULL)
02805                                 dns_acl_detach(&mapped);
02806                         if (excluded != NULL)
02807                                 dns_acl_detach(&excluded);
02808                 }
02809         }
02810 
02811         obj = NULL;
02812         result = ns_config_get(maps, "dnssec-accept-expired", &obj);
02813         INSIST(result == ISC_R_SUCCESS);
02814         view->acceptexpired = cfg_obj_asboolean(obj);
02815 
02816         obj = NULL;
02817         result = ns_config_get(maps, "dnssec-validation", &obj);
02818         INSIST(result == ISC_R_SUCCESS);
02819         if (cfg_obj_isboolean(obj)) {
02820                 view->enablevalidation = cfg_obj_asboolean(obj);
02821         } else {
02822                 /* If dnssec-validation is not boolean, it must be "auto" */
02823                 view->enablevalidation = ISC_TRUE;
02824                 auto_root = ISC_TRUE;
02825         }
02826 
02827         obj = NULL;
02828         result = ns_config_get(maps, "max-cache-ttl", &obj);
02829         INSIST(result == ISC_R_SUCCESS);
02830         view->maxcachettl = cfg_obj_asuint32(obj);
02831 
02832         obj = NULL;
02833         result = ns_config_get(maps, "max-ncache-ttl", &obj);
02834         INSIST(result == ISC_R_SUCCESS);
02835         view->maxncachettl = cfg_obj_asuint32(obj);
02836         if (view->maxncachettl > 7 * 24 * 3600)
02837                 view->maxncachettl = 7 * 24 * 3600;
02838 
02839         /*
02840          * Configure the view's cache.
02841          *
02842          * First, check to see if there are any attach-cache options.  If yes,
02843          * attempt to lookup an existing cache at attach it to the view.  If
02844          * there is not one, then try to reuse an existing cache if possible;
02845          * otherwise create a new cache.
02846          *
02847          * Note that the ADB is not preserved or shared in either case.
02848          *
02849          * When a matching view is found, the associated statistics are also
02850          * retrieved and reused.
02851          *
02852          * XXX Determining when it is safe to reuse or share a cache is tricky.
02853          * When the view's configuration changes, the cached data may become
02854          * invalid because it reflects our old view of the world.  We check
02855          * some of the configuration parameters that could invalidate the cache
02856          * or otherwise make it unsharable, but there are other configuration
02857          * options that should be checked.  For example, if a view uses a
02858          * forwarder, changes in the forwarder configuration may invalidate
02859          * the cache.  At the moment, it's the administrator's responsibility to
02860          * ensure these configuration options don't invalidate reusing/sharing.
02861          */
02862         obj = NULL;
02863         result = ns_config_get(maps, "attach-cache", &obj);
02864         if (result == ISC_R_SUCCESS)
02865                 cachename = cfg_obj_asstring(obj);
02866         else
02867                 cachename = view->name;
02868         cache = NULL;
02869         nsc = cachelist_find(cachelist, cachename);
02870         if (nsc != NULL) {
02871                 if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
02872                                     cleaning_interval, max_cache_size)) {
02873                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
02874                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
02875                                       "views %s and %s can't share the cache "
02876                                       "due to configuration parameter mismatch",
02877                                       nsc->primaryview->name, view->name);
02878                         result = ISC_R_FAILURE;
02879                         goto cleanup;
02880                 }
02881                 dns_cache_attach(nsc->cache, &cache);
02882                 shared_cache = ISC_TRUE;
02883         } else {
02884                 if (strcmp(cachename, view->name) == 0) {
02885                         result = dns_viewlist_find(&ns_g_server->viewlist,
02886                                                    cachename, view->rdclass,
02887                                                    &pview);
02888                         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
02889                                 goto cleanup;
02890                         if (pview != NULL) {
02891                                 if (!cache_reusable(pview, view,
02892                                                     zero_no_soattl)) {
02893                                         isc_log_write(ns_g_lctx,
02894                                                       NS_LOGCATEGORY_GENERAL,
02895                                                       NS_LOGMODULE_SERVER,
02896                                                       ISC_LOG_DEBUG(1),
02897                                                       "cache cannot be reused "
02898                                                       "for view %s due to "
02899                                                       "configuration parameter "
02900                                                       "mismatch", view->name);
02901                                 } else {
02902                                         INSIST(pview->cache != NULL);
02903                                         isc_log_write(ns_g_lctx,
02904                                                       NS_LOGCATEGORY_GENERAL,
02905                                                       NS_LOGMODULE_SERVER,
02906                                                       ISC_LOG_DEBUG(3),
02907                                                       "reusing existing cache");
02908                                         reused_cache = ISC_TRUE;
02909                                         dns_cache_attach(pview->cache, &cache);
02910                                 }
02911                                 dns_view_getresstats(pview, &resstats);
02912                                 dns_view_getresquerystats(pview,
02913                                                           &resquerystats);
02914                                 dns_view_detach(&pview);
02915                         }
02916                 }
02917                 if (cache == NULL) {
02918                         /*
02919                          * Create a cache with the desired name.  This normally
02920                          * equals the view name, but may also be a forward
02921                          * reference to a view that share the cache with this
02922                          * view but is not yet configured.  If it is not the
02923                          * view name but not a forward reference either, then it
02924                          * is simply a named cache that is not shared.
02925                          *
02926                          * We use two separate memory contexts for the
02927                          * cache, for the main cache memory and the heap
02928                          * memory.
02929                          */
02930                         CHECK(isc_mem_create(0, 0, &cmctx));
02931                         isc_mem_setname(cmctx, "cache", NULL);
02932                         CHECK(isc_mem_create(0, 0, &hmctx));
02933                         isc_mem_setname(hmctx, "cache_heap", NULL);
02934                         CHECK(dns_cache_create3(cmctx, hmctx, ns_g_taskmgr,
02935                                                 ns_g_timermgr, view->rdclass,
02936                                                 cachename, "rbt", 0, NULL,
02937                                                 &cache));
02938                         isc_mem_detach(&cmctx);
02939                         isc_mem_detach(&hmctx);
02940                 }
02941                 nsc = isc_mem_get(mctx, sizeof(*nsc));
02942                 if (nsc == NULL) {
02943                         result = ISC_R_NOMEMORY;
02944                         goto cleanup;
02945                 }
02946                 nsc->cache = NULL;
02947                 dns_cache_attach(cache, &nsc->cache);
02948                 nsc->primaryview = view;
02949                 nsc->needflush = ISC_FALSE;
02950                 nsc->adbsizeadjusted = ISC_FALSE;
02951                 ISC_LINK_INIT(nsc, link);
02952                 ISC_LIST_APPEND(*cachelist, nsc, link);
02953         }
02954         dns_view_setcache2(view, cache, shared_cache);
02955 
02956         /*
02957          * cache-file cannot be inherited if views are present, but this
02958          * should be caught by the configuration checking stage.
02959          */
02960         obj = NULL;
02961         result = ns_config_get(maps, "cache-file", &obj);
02962         if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
02963                 CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
02964                 if (!reused_cache && !shared_cache)
02965                         CHECK(dns_cache_load(cache));
02966         }
02967 
02968         dns_cache_setcleaninginterval(cache, cleaning_interval);
02969         dns_cache_setcachesize(cache, max_cache_size);
02970 
02971         dns_cache_detach(&cache);
02972 
02973         /*
02974          * Resolver.
02975          *
02976          * XXXRTH  Hardwired number of tasks.
02977          */
02978         CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4, &dscp4,
02979                                             ISC_TF(ISC_LIST_PREV(view, link)
02980                                                    == NULL)));
02981         CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6, &dscp6,
02982                                             ISC_TF(ISC_LIST_PREV(view, link)
02983                                                    == NULL)));
02984         if (dispatch4 == NULL && dispatch6 == NULL) {
02985                 UNEXPECTED_ERROR(__FILE__, __LINE__,
02986                                  "unable to obtain neither an IPv4 nor"
02987                                  " an IPv6 dispatch");
02988                 result = ISC_R_UNEXPECTED;
02989                 goto cleanup;
02990         }
02991 
02992         if (resstats == NULL) {
02993                 CHECK(isc_stats_create(mctx, &resstats,
02994                                        dns_resstatscounter_max));
02995         }
02996         dns_view_setresstats(view, resstats);
02997         if (resquerystats == NULL)
02998                 CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
02999         dns_view_setresquerystats(view, resquerystats);
03000 
03001         ndisp = 4 * ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH);
03002         CHECK(dns_view_createresolver(view, ns_g_taskmgr, RESOLVER_NTASKS,
03003                                       ndisp, ns_g_socketmgr, ns_g_timermgr,
03004                                       resopts, ns_g_dispatchmgr,
03005                                       dispatch4, dispatch6));
03006 
03007         if (dscp4 == -1)
03008                 dscp4 = ns_g_dscp;
03009         if (dscp6 == -1)
03010                 dscp6 = ns_g_dscp;
03011         if (dscp4 != -1)
03012                 dns_resolver_setquerydscp4(view->resolver, dscp4);
03013         if (dscp6 != -1)
03014                 dns_resolver_setquerydscp6(view->resolver, dscp6);
03015 
03016         /*
03017          * Set the ADB cache size to 1/8th of the max-cache-size or
03018          * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
03019          */
03020         max_adb_size = 0;
03021         if (max_cache_size != 0U) {
03022                 max_adb_size = max_cache_size / 8;
03023                 if (max_adb_size == 0U)
03024                         max_adb_size = 1;       /* Force minimum. */
03025                 if (view != nsc->primaryview &&
03026                     max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) {
03027                         max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
03028                         if (!nsc->adbsizeadjusted) {
03029                                 dns_adb_setadbsize(nsc->primaryview->adb,
03030                                                    MAX_ADB_SIZE_FOR_CACHESHARE);
03031                                 nsc->adbsizeadjusted = ISC_TRUE;
03032                         }
03033                 }
03034         }
03035         dns_adb_setadbsize(view->adb, max_adb_size);
03036 
03037         /*
03038          * Set resolver's lame-ttl.
03039          */
03040         obj = NULL;
03041         result = ns_config_get(maps, "lame-ttl", &obj);
03042         INSIST(result == ISC_R_SUCCESS);
03043         lame_ttl = cfg_obj_asuint32(obj);
03044         if (lame_ttl > 1800)
03045                 lame_ttl = 1800;
03046         dns_resolver_setlamettl(view->resolver, lame_ttl);
03047 
03048         /*
03049          * Set the resolver's query timeout.
03050          */
03051         obj = NULL;
03052         result = ns_config_get(maps, "resolver-query-timeout", &obj);
03053         INSIST(result == ISC_R_SUCCESS);
03054         query_timeout = cfg_obj_asuint32(obj);
03055         dns_resolver_settimeout(view->resolver, query_timeout);
03056 
03057         /* Specify whether to use 0-TTL for negative response for SOA query */
03058         dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
03059 
03060         /*
03061          * Set the resolver's EDNS UDP size.
03062          */
03063         obj = NULL;
03064         result = ns_config_get(maps, "edns-udp-size", &obj);
03065         INSIST(result == ISC_R_SUCCESS);
03066         udpsize = cfg_obj_asuint32(obj);
03067         if (udpsize < 512)
03068                 udpsize = 512;
03069         if (udpsize > 4096)
03070                 udpsize = 4096;
03071         dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize);
03072 
03073         /*
03074          * Set the maximum UDP response size.
03075          */
03076         obj = NULL;
03077         result = ns_config_get(maps, "max-udp-size", &obj);
03078         INSIST(result == ISC_R_SUCCESS);
03079         udpsize = cfg_obj_asuint32(obj);
03080         if (udpsize < 512)
03081                 udpsize = 512;
03082         if (udpsize > 4096)
03083                 udpsize = 4096;
03084         view->maxudp = udpsize;
03085 
03086 #ifdef ISC_PLATFORM_USESIT
03087         /*
03088          * Set the maximum UDP when a SIT is not provided.
03089          */
03090         obj = NULL;
03091         result = ns_config_get(maps, "nosit-udp-size", &obj);
03092         INSIST(result == ISC_R_SUCCESS);
03093         udpsize = cfg_obj_asuint32(obj);
03094         if (udpsize < 128)
03095                 udpsize = 128;
03096         if (udpsize > view->maxudp)
03097                 udpsize = view->maxudp;
03098         view->situdp = udpsize;
03099 #endif
03100 
03101         /*
03102          * Set the maximum rsa exponent bits.
03103          */
03104         obj = NULL;
03105         result = ns_config_get(maps, "max-rsa-exponent-size", &obj);
03106         INSIST(result == ISC_R_SUCCESS);
03107         maxbits = cfg_obj_asuint32(obj);
03108         if (maxbits != 0 && maxbits < 35)
03109                 maxbits = 35;
03110         if (maxbits > 4096)
03111                 maxbits = 4096;
03112         view->maxbits = maxbits;
03113 
03114         /*
03115          * Set supported DNSSEC algorithms.
03116          */
03117         dns_resolver_reset_algorithms(view->resolver);
03118         disabled = NULL;
03119         (void)ns_config_get(maps, "disable-algorithms", &disabled);
03120         if (disabled != NULL) {
03121                 for (element = cfg_list_first(disabled);
03122                      element != NULL;
03123                      element = cfg_list_next(element))
03124                         CHECK(disable_algorithms(cfg_listelt_value(element),
03125                                                  view->resolver));
03126         }
03127 
03128         /*
03129          * Set supported DS/DLV digest types.
03130          */
03131         dns_resolver_reset_ds_digests(view->resolver);
03132         disabled = NULL;
03133         (void)ns_config_get(maps, "disable-ds-digests", &disabled);
03134         if (disabled != NULL) {
03135                 for (element = cfg_list_first(disabled);
03136                      element != NULL;
03137                      element = cfg_list_next(element))
03138                         CHECK(disable_ds_digests(cfg_listelt_value(element),
03139                                                  view->resolver));
03140         }
03141 
03142         /*
03143          * A global or view "forwarders" option, if present,
03144          * creates an entry for "." in the forwarding table.
03145          */
03146         forwardtype = NULL;
03147         forwarders = NULL;
03148         (void)ns_config_get(maps, "forward", &forwardtype);
03149         (void)ns_config_get(maps, "forwarders", &forwarders);
03150         if (forwarders != NULL)
03151                 CHECK(configure_forward(config, view, dns_rootname,
03152                                         forwarders, forwardtype));
03153 
03154         /*
03155          * Dual Stack Servers.
03156          */
03157         alternates = NULL;
03158         (void)ns_config_get(maps, "dual-stack-servers", &alternates);
03159         if (alternates != NULL)
03160                 CHECK(configure_alternates(config, view, alternates));
03161 
03162         /*
03163          * We have default hints for class IN if we need them.
03164          */
03165         if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
03166                 dns_view_sethints(view, ns_g_server->in_roothints);
03167 
03168         /*
03169          * If we still have no hints, this is a non-IN view with no
03170          * "hints zone" configured.  Issue a warning, except if this
03171          * is a root server.  Root servers never need to consult
03172          * their hints, so it's no point requiring users to configure
03173          * them.
03174          */
03175         if (view->hints == NULL) {
03176                 dns_zone_t *rootzone = NULL;
03177                 (void)dns_view_findzone(view, dns_rootname, &rootzone);
03178                 if (rootzone != NULL) {
03179                         dns_zone_detach(&rootzone);
03180                         need_hints = ISC_FALSE;
03181                 }
03182                 if (need_hints)
03183                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
03184                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
03185                                       "no root hints for view '%s'",
03186                                       view->name);
03187         }
03188 
03189         /*
03190          * Configure the view's TSIG keys.
03191          */
03192         CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
03193         if (ns_g_server->sessionkey != NULL) {
03194                 CHECK(dns_tsigkeyring_add(ring, ns_g_server->session_keyname,
03195                                           ns_g_server->sessionkey));
03196         }
03197         dns_view_setkeyring(view, ring);
03198         dns_tsigkeyring_detach(&ring);
03199 
03200         /*
03201          * See if we can re-use a dynamic key ring.
03202          */
03203         result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
03204                                    view->rdclass, &pview);
03205         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
03206                 goto cleanup;
03207         if (pview != NULL) {
03208                 dns_view_getdynamickeyring(pview, &ring);
03209                 if (ring != NULL)
03210                         dns_view_setdynamickeyring(view, ring);
03211                 dns_tsigkeyring_detach(&ring);
03212                 dns_view_detach(&pview);
03213         } else
03214                 dns_view_restorekeyring(view);
03215 
03216         /*
03217          * Configure the view's peer list.
03218          */
03219         {
03220                 const cfg_obj_t *peers = NULL;
03221                 dns_peerlist_t *newpeers = NULL;
03222 
03223                 (void)ns_config_get(cfgmaps, "server", &peers);
03224                 CHECK(dns_peerlist_new(mctx, &newpeers));
03225                 for (element = cfg_list_first(peers);
03226                      element != NULL;
03227                      element = cfg_list_next(element))
03228                 {
03229                         const cfg_obj_t *cpeer = cfg_listelt_value(element);
03230                         dns_peer_t *peer;
03231 
03232                         CHECK(configure_peer(cpeer, mctx, &peer));
03233                         dns_peerlist_addpeer(newpeers, peer);
03234                         dns_peer_detach(&peer);
03235                 }
03236                 dns_peerlist_detach(&view->peers);
03237                 view->peers = newpeers; /* Transfer ownership. */
03238         }
03239 
03240         /*
03241          *      Configure the views rrset-order.
03242          */
03243         {
03244                 const cfg_obj_t *rrsetorder = NULL;
03245 
03246                 (void)ns_config_get(maps, "rrset-order", &rrsetorder);
03247                 CHECK(dns_order_create(mctx, &order));
03248                 for (element = cfg_list_first(rrsetorder);
03249                      element != NULL;
03250                      element = cfg_list_next(element))
03251                 {
03252                         const cfg_obj_t *ent = cfg_listelt_value(element);
03253 
03254                         CHECK(configure_order(order, ent));
03255                 }
03256                 if (view->order != NULL)
03257                         dns_order_detach(&view->order);
03258                 dns_order_attach(order, &view->order);
03259                 dns_order_detach(&order);
03260         }
03261         /*
03262          * Copy the aclenv object.
03263          */
03264         dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv);
03265 
03266         /*
03267          * Configure the "match-clients" and "match-destinations" ACL.
03268          */
03269         CHECK(configure_view_acl(vconfig, config, "match-clients", NULL, actx,
03270                                  ns_g_mctx, &view->matchclients));
03271         CHECK(configure_view_acl(vconfig, config, "match-destinations", NULL,
03272                                  actx, ns_g_mctx, &view->matchdestinations));
03273 
03274         /*
03275          * Configure the "match-recursive-only" option.
03276          */
03277         obj = NULL;
03278         (void)ns_config_get(maps, "match-recursive-only", &obj);
03279         if (obj != NULL && cfg_obj_asboolean(obj))
03280                 view->matchrecursiveonly = ISC_TRUE;
03281         else
03282                 view->matchrecursiveonly = ISC_FALSE;
03283 
03284         /*
03285          * Configure other configurable data.
03286          */
03287         obj = NULL;
03288         result = ns_config_get(maps, "recursion", &obj);
03289         INSIST(result == ISC_R_SUCCESS);
03290         view->recursion = cfg_obj_asboolean(obj);
03291 
03292         obj = NULL;
03293         result = ns_config_get(maps, "auth-nxdomain", &obj);
03294         INSIST(result == ISC_R_SUCCESS);
03295         view->auth_nxdomain = cfg_obj_asboolean(obj);
03296 
03297         obj = NULL;
03298         result = ns_config_get(maps, "minimal-responses", &obj);
03299         INSIST(result == ISC_R_SUCCESS);
03300         view->minimalresponses = cfg_obj_asboolean(obj);
03301 
03302         obj = NULL;
03303         result = ns_config_get(maps, "transfer-format", &obj);
03304         INSIST(result == ISC_R_SUCCESS);
03305         str = cfg_obj_asstring(obj);
03306         if (strcasecmp(str, "many-answers") == 0)
03307                 view->transfer_format = dns_many_answers;
03308         else if (strcasecmp(str, "one-answer") == 0)
03309                 view->transfer_format = dns_one_answer;
03310         else
03311                 INSIST(0);
03312 
03313         /*
03314          * Set sources where additional data and CNAME/DNAME
03315          * targets for authoritative answers may be found.
03316          */
03317         obj = NULL;
03318         result = ns_config_get(maps, "additional-from-auth", &obj);
03319         INSIST(result == ISC_R_SUCCESS);
03320         view->additionalfromauth = cfg_obj_asboolean(obj);
03321         if (view->recursion && ! view->additionalfromauth) {
03322                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
03323                             "'additional-from-auth no' is only supported "
03324                             "with 'recursion no'");
03325                 view->additionalfromauth = ISC_TRUE;
03326         }
03327 
03328         obj = NULL;
03329         result = ns_config_get(maps, "additional-from-cache", &obj);
03330         INSIST(result == ISC_R_SUCCESS);
03331         view->additionalfromcache = cfg_obj_asboolean(obj);
03332         if (view->recursion && ! view->additionalfromcache) {
03333                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
03334                             "'additional-from-cache no' is only supported "
03335                             "with 'recursion no'");
03336                 view->additionalfromcache = ISC_TRUE;
03337         }
03338 
03339         /*
03340          * Set "allow-query-cache", "allow-query-cache-on",
03341          * "allow-recursion", and "allow-recursion-on" acls if
03342          * configured in named.conf.
03343          */
03344         CHECK(configure_view_acl(vconfig, config, "allow-query-cache", NULL,
03345                                  actx, ns_g_mctx, &view->cacheacl));
03346         CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", NULL,
03347                                  actx, ns_g_mctx, &view->cacheonacl));
03348         if (view->cacheonacl == NULL)
03349                 CHECK(configure_view_acl(NULL, ns_g_config,
03350                                          "allow-query-cache-on", NULL, actx,
03351                                          ns_g_mctx, &view->cacheonacl));
03352         if (strcmp(view->name, "_bind") != 0) {
03353                 CHECK(configure_view_acl(vconfig, config, "allow-recursion",
03354                                          NULL, actx, ns_g_mctx,
03355                                          &view->recursionacl));
03356                 CHECK(configure_view_acl(vconfig, config, "allow-recursion-on",
03357                                          NULL, actx, ns_g_mctx,
03358                                          &view->recursiononacl));
03359         }
03360 
03361         /*
03362          * "allow-query-cache" inherits from "allow-recursion" if set,
03363          * otherwise from "allow-query" if set.
03364          * "allow-recursion" inherits from "allow-query-cache" if set,
03365          * otherwise from "allow-query" if set.
03366          */
03367         if (view->cacheacl == NULL && view->recursionacl != NULL)
03368                 dns_acl_attach(view->recursionacl, &view->cacheacl);
03369         /*
03370          * XXXEACH: This call to configure_view_acl() is redundant.  We
03371          * are leaving it as it is because we are making a minimal change
03372          * for a patch release.  In the future this should be changed to
03373          * dns_acl_attach(view->queryacl, &view->cacheacl).
03374          */
03375         if (view->cacheacl == NULL && view->recursion)
03376                 CHECK(configure_view_acl(vconfig, config, "allow-query", NULL,
03377                                          actx, ns_g_mctx, &view->cacheacl));
03378         if (view->recursion &&
03379             view->recursionacl == NULL && view->cacheacl != NULL)
03380                 dns_acl_attach(view->cacheacl, &view->recursionacl);
03381 
03382         /*
03383          * Set default "allow-recursion", "allow-recursion-on" and
03384          * "allow-query-cache" acls.
03385          */
03386         if (view->recursionacl == NULL && view->recursion)
03387                 CHECK(configure_view_acl(NULL, ns_g_config,
03388                                          "allow-recursion", NULL,
03389                                          actx, ns_g_mctx,
03390                                          &view->recursionacl));
03391         if (view->recursiononacl == NULL && view->recursion)
03392                 CHECK(configure_view_acl(NULL, ns_g_config,
03393                                          "allow-recursion-on", NULL,
03394                                          actx, ns_g_mctx,
03395                                          &view->recursiononacl));
03396         if (view->cacheacl == NULL) {
03397                 if (view->recursion)
03398                         CHECK(configure_view_acl(NULL, ns_g_config,
03399                                                  "allow-query-cache", NULL,
03400                                                  actx, ns_g_mctx,
03401                                                  &view->cacheacl));
03402                 else
03403                         CHECK(dns_acl_none(mctx, &view->cacheacl));
03404         }
03405 
03406         /*
03407          * Ignore case when compressing responses to the specified
03408          * clients. This causes case not always to be preserved,
03409          * and is needed by some broken clients.
03410          */
03411         CHECK(configure_view_acl(vconfig, config, "no-case-compress", NULL,
03412                                  actx, ns_g_mctx, &view->nocasecompress));
03413 
03414         /*
03415          * Filter setting on addresses in the answer section.
03416          */
03417         CHECK(configure_view_acl(vconfig, config, "deny-answer-addresses",
03418                                  "acl", actx, ns_g_mctx, &view->denyansweracl));
03419         CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
03420                                        "except-from", ns_g_mctx,
03421                                        &view->answeracl_exclude));
03422 
03423         /*
03424          * Filter setting on names (CNAME/DNAME targets) in the answer section.
03425          */
03426         CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
03427                                        "name", ns_g_mctx,
03428                                        &view->denyanswernames));
03429         CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
03430                                        "except-from", ns_g_mctx,
03431                                        &view->answernames_exclude));
03432 
03433         /*
03434          * Configure sortlist, if set
03435          */
03436         CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx,
03437                                       &view->sortlist));
03438 
03439         /*
03440          * Configure default allow-transfer, allow-notify, allow-update
03441          * and allow-update-forwarding ACLs, if set, so they can be
03442          * inherited by zones.
03443          */
03444         if (view->notifyacl == NULL)
03445                 CHECK(configure_view_acl(NULL, ns_g_config,
03446                                          "allow-notify", NULL, actx,
03447                                          ns_g_mctx, &view->notifyacl));
03448         if (view->transferacl == NULL)
03449                 CHECK(configure_view_acl(NULL, ns_g_config,
03450                                          "allow-transfer", NULL, actx,
03451                                          ns_g_mctx, &view->transferacl));
03452         if (view->updateacl == NULL)
03453                 CHECK(configure_view_acl(NULL, ns_g_config,
03454                                          "allow-update", NULL, actx,
03455                                          ns_g_mctx, &view->updateacl));
03456         if (view->upfwdacl == NULL)
03457                 CHECK(configure_view_acl(NULL, ns_g_config,
03458                                          "allow-update-forwarding", NULL, actx,
03459                                          ns_g_mctx, &view->upfwdacl));
03460 
03461         obj = NULL;
03462         result = ns_config_get(maps, "provide-ixfr", &obj);
03463         INSIST(result == ISC_R_SUCCESS);
03464         view->provideixfr = cfg_obj_asboolean(obj);
03465 
03466         obj = NULL;
03467         result = ns_config_get(maps, "request-nsid", &obj);
03468         INSIST(result == ISC_R_SUCCESS);
03469         view->requestnsid = cfg_obj_asboolean(obj);
03470 
03471 #ifdef ISC_PLATFORM_USESIT
03472         obj = NULL;
03473         result = ns_config_get(maps, "request-sit", &obj);
03474         INSIST(result == ISC_R_SUCCESS);
03475         view->requestsit = cfg_obj_asboolean(obj);
03476 #endif
03477 
03478         obj = NULL;
03479         result = ns_config_get(maps, "max-clients-per-query", &obj);
03480         INSIST(result == ISC_R_SUCCESS);
03481         max_clients_per_query = cfg_obj_asuint32(obj);
03482 
03483         obj = NULL;
03484         result = ns_config_get(maps, "clients-per-query", &obj);
03485         INSIST(result == ISC_R_SUCCESS);
03486         dns_resolver_setclientsperquery(view->resolver,
03487                                         cfg_obj_asuint32(obj),
03488                                         max_clients_per_query);
03489 
03490         obj = NULL;
03491         result = ns_config_get(maps, "max-recursion-depth", &obj);
03492         INSIST(result == ISC_R_SUCCESS);
03493         dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
03494 
03495         obj = NULL;
03496         result = ns_config_get(maps, "max-recursion-queries", &obj);
03497         INSIST(result == ISC_R_SUCCESS);
03498         dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
03499 
03500 #ifdef ALLOW_FILTER_AAAA
03501         obj = NULL;
03502         result = ns_config_get(maps, "filter-aaaa-on-v4", &obj);
03503         INSIST(result == ISC_R_SUCCESS);
03504         if (cfg_obj_isboolean(obj)) {
03505                 if (cfg_obj_asboolean(obj))
03506                         view->v4_aaaa = dns_aaaa_filter;
03507                 else
03508                         view->v4_aaaa = dns_aaaa_ok;
03509         } else {
03510                 const char *v4_aaaastr = cfg_obj_asstring(obj);
03511                 if (strcasecmp(v4_aaaastr, "break-dnssec") == 0)
03512                         view->v4_aaaa = dns_aaaa_break_dnssec;
03513                 else
03514                         INSIST(0);
03515         }
03516 
03517         obj = NULL;
03518         result = ns_config_get(maps, "filter-aaaa-on-v6", &obj);
03519         INSIST(result == ISC_R_SUCCESS);
03520         if (cfg_obj_isboolean(obj)) {
03521                 if (cfg_obj_asboolean(obj))
03522                         view->v6_aaaa = dns_aaaa_filter;
03523                 else
03524                         view->v6_aaaa = dns_aaaa_ok;
03525         } else {
03526                 const char *v6_aaaastr = cfg_obj_asstring(obj);
03527                 if (strcasecmp(v6_aaaastr, "break-dnssec") == 0)
03528                         view->v6_aaaa = dns_aaaa_break_dnssec;
03529                 else
03530                         INSIST(0);
03531         }
03532 
03533         CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL,
03534                                  actx, ns_g_mctx, &view->aaaa_acl));
03535 #endif
03536         obj = NULL;
03537         result = ns_config_get(maps, "prefetch", &obj);
03538         if (result == ISC_R_SUCCESS) {
03539                 const cfg_obj_t *trigger, *eligible;
03540 
03541                 trigger = cfg_tuple_get(obj, "trigger");
03542                 view->prefetch_trigger = cfg_obj_asuint32(trigger);
03543                 if (view->prefetch_trigger > 10)
03544                         view->prefetch_trigger = 10;
03545                 eligible = cfg_tuple_get(obj, "eligible");
03546                 if (cfg_obj_isvoid(eligible)) {
03547                         int m;
03548                         for (m = 1; maps[m] != NULL; m++) {
03549                                 obj = NULL;
03550                                 result = ns_config_get(&maps[m],
03551                                                        "prefetch", &obj);
03552                                 INSIST(result == ISC_R_SUCCESS);
03553                                 eligible = cfg_tuple_get(obj, "eligible");
03554                                 if (cfg_obj_isuint32(eligible))
03555                                         break;
03556                         }
03557                         INSIST(cfg_obj_isuint32(eligible));
03558                 }
03559                 view->prefetch_eligible = cfg_obj_asuint32(eligible);
03560                 if (view->prefetch_eligible < view->prefetch_trigger + 6)
03561                         view->prefetch_eligible = view->prefetch_trigger + 6;
03562         }
03563 
03564         obj = NULL;
03565         result = ns_config_get(maps, "dnssec-enable", &obj);
03566         INSIST(result == ISC_R_SUCCESS);
03567         view->enablednssec = cfg_obj_asboolean(obj);
03568 
03569         obj = NULL;
03570         result = ns_config_get(optionmaps, "dnssec-lookaside", &obj);
03571         if (result == ISC_R_SUCCESS) {
03572                 /* If set to "auto", use the version from the defaults */
03573                 const cfg_obj_t *dlvobj;
03574                 const char *dom;
03575                 dlvobj = cfg_listelt_value(cfg_list_first(obj));
03576                 dom = cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain"));
03577                 if (cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) {
03578                         /* If "no", skip; if "auto", use global default */
03579                         if (!strcasecmp(dom, "no"))
03580                                 result = ISC_R_NOTFOUND;
03581                         else if (!strcasecmp(dom, "auto")) {
03582                                 auto_dlv = ISC_TRUE;
03583                                 obj = NULL;
03584                                 result = cfg_map_get(ns_g_defaults,
03585                                                      "dnssec-lookaside", &obj);
03586                         }
03587                 }
03588         }
03589 
03590         if (result == ISC_R_SUCCESS) {
03591                 for (element = cfg_list_first(obj);
03592                      element != NULL;
03593                      element = cfg_list_next(element))
03594                 {
03595                         dns_name_t *dlv;
03596 
03597                         obj = cfg_listelt_value(element);
03598                         obj = cfg_tuple_get(obj, "trust-anchor");
03599                         dlv = dns_fixedname_name(&view->dlv_fixed);
03600                         CHECK(dns_name_fromstring(dlv, cfg_obj_asstring(obj),
03601                                                   DNS_NAME_DOWNCASE, NULL));
03602                         view->dlv = dns_fixedname_name(&view->dlv_fixed);
03603                 }
03604         } else
03605                 view->dlv = NULL;
03606 
03607         /*
03608          * For now, there is only one kind of trusted keys, the
03609          * "security roots".
03610          */
03611         CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
03612                                         auto_dlv, auto_root, mctx));
03613         dns_resolver_resetmustbesecure(view->resolver);
03614         obj = NULL;
03615         result = ns_config_get(maps, "dnssec-must-be-secure", &obj);
03616         if (result == ISC_R_SUCCESS)
03617                 CHECK(mustbesecure(obj, view->resolver));
03618 
03619         obj = NULL;
03620         result = ns_config_get(maps, "nta-recheck", &obj);
03621         INSIST(result == ISC_R_SUCCESS);
03622         view->nta_recheck = cfg_obj_asuint32(obj);
03623 
03624         obj = NULL;
03625         result = ns_config_get(maps, "nta-lifetime", &obj);
03626         INSIST(result == ISC_R_SUCCESS);
03627         view->nta_lifetime = cfg_obj_asuint32(obj);
03628 
03629         obj = NULL;
03630         result = ns_config_get(maps, "preferred-glue", &obj);
03631         if (result == ISC_R_SUCCESS) {
03632                 str = cfg_obj_asstring(obj);
03633                 if (strcasecmp(str, "a") == 0)
03634                         view->preferred_glue = dns_rdatatype_a;
03635                 else if (strcasecmp(str, "aaaa") == 0)
03636                         view->preferred_glue = dns_rdatatype_aaaa;
03637                 else
03638                         view->preferred_glue = 0;
03639         } else
03640                 view->preferred_glue = 0;
03641 
03642         obj = NULL;
03643         result = ns_config_get(maps, "root-delegation-only", &obj);
03644         if (result == ISC_R_SUCCESS) {
03645                 dns_fixedname_t fixed;
03646                 dns_name_t *name;
03647                 const cfg_obj_t *exclude;
03648 
03649                 dns_view_setrootdelonly(view, ISC_TRUE);
03650 
03651                 dns_fixedname_init(&fixed);
03652                 name = dns_fixedname_name(&fixed);
03653                 for (element = cfg_list_first(obj);
03654                      element != NULL;
03655                      element = cfg_list_next(element)) {
03656                         exclude = cfg_listelt_value(element);
03657                         CHECK(dns_name_fromstring(name,
03658                                                   cfg_obj_asstring(exclude),
03659                                                   0, NULL));
03660                         CHECK(dns_view_excludedelegationonly(view, name));
03661                 }
03662         } else
03663                 dns_view_setrootdelonly(view, ISC_FALSE);
03664 
03665         /*
03666          * Setup automatic empty zones.  If recursion is off then
03667          * they are disabled by default.
03668          */
03669         obj = NULL;
03670         (void)ns_config_get(maps, "empty-zones-enable", &obj);
03671         (void)ns_config_get(maps, "disable-empty-zone", &disablelist);
03672         if (obj == NULL && disablelist == NULL &&
03673             view->rdclass == dns_rdataclass_in) {
03674                 empty_zones_enable = view->recursion;
03675         } else if (view->rdclass == dns_rdataclass_in) {
03676                 if (obj != NULL)
03677                         empty_zones_enable = cfg_obj_asboolean(obj);
03678                 else
03679                         empty_zones_enable = view->recursion;
03680         } else {
03681                 empty_zones_enable = ISC_FALSE;
03682         }
03683 
03684         if (empty_zones_enable && !lwresd_g_useresolvconf) {
03685                 const char *empty;
03686                 int empty_zone = 0;
03687                 dns_fixedname_t fixed;
03688                 dns_name_t *name;
03689                 isc_buffer_t buffer;
03690                 char server[DNS_NAME_FORMATSIZE + 1];
03691                 char contact[DNS_NAME_FORMATSIZE + 1];
03692                 const char *empty_dbtype[4] =
03693                                     { "_builtin", "empty", NULL, NULL };
03694                 int empty_dbtypec = 4;
03695                 dns_zonestat_level_t statlevel;
03696 
03697                 dns_fixedname_init(&fixed);
03698                 name = dns_fixedname_name(&fixed);
03699 
03700                 obj = NULL;
03701                 result = ns_config_get(maps, "empty-server", &obj);
03702                 if (result == ISC_R_SUCCESS) {
03703                         CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
03704                                                   0, NULL));
03705                         isc_buffer_init(&buffer, server, sizeof(server) - 1);
03706                         CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
03707                         server[isc_buffer_usedlength(&buffer)] = 0;
03708                         empty_dbtype[2] = server;
03709                 } else
03710                         empty_dbtype[2] = "@";
03711 
03712                 obj = NULL;
03713                 result = ns_config_get(maps, "empty-contact", &obj);
03714                 if (result == ISC_R_SUCCESS) {
03715                         CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
03716                                                  0, NULL));
03717                         isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
03718                         CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
03719                         contact[isc_buffer_usedlength(&buffer)] = 0;
03720                         empty_dbtype[3] = contact;
03721                 } else
03722                         empty_dbtype[3] = ".";
03723 
03724                 obj = NULL;
03725                 result = ns_config_get(maps, "zone-statistics", &obj);
03726                 INSIST(result == ISC_R_SUCCESS);
03727                 if (cfg_obj_isboolean(obj)) {
03728                         if (cfg_obj_asboolean(obj))
03729                                 statlevel = dns_zonestat_full;
03730                         else
03731                                 statlevel = dns_zonestat_none;
03732                 } else {
03733                         const char *levelstr = cfg_obj_asstring(obj);
03734                         if (strcasecmp(levelstr, "full") == 0)
03735                                 statlevel = dns_zonestat_full;
03736                         else if (strcasecmp(levelstr, "terse") == 0)
03737                                 statlevel = dns_zonestat_terse;
03738                         else if (strcasecmp(levelstr, "none") == 0)
03739                                 statlevel = dns_zonestat_none;
03740                         else
03741                                 INSIST(0);
03742                 }
03743 
03744                 for (empty = empty_zones[empty_zone];
03745                      empty != NULL;
03746                      empty = empty_zones[++empty_zone])
03747                 {
03748                         dns_forwarders_t *dnsforwarders = NULL;
03749 
03750                         /*
03751                          * Look for zone on drop list.
03752                          */
03753                         CHECK(dns_name_fromstring(name, empty, 0, NULL));
03754                         if (disablelist != NULL &&
03755                             on_disable_list(disablelist, name))
03756                                 continue;
03757 
03758                         /*
03759                          * This zone already exists.
03760                          */
03761                         (void)dns_view_findzone(view, name, &zone);
03762                         if (zone != NULL) {
03763                                 dns_zone_detach(&zone);
03764                                 continue;
03765                         }
03766 
03767                         /*
03768                          * If we would forward this name don't add a
03769                          * empty zone for it.
03770                          */
03771                         result = dns_fwdtable_find(view->fwdtable, name,
03772                                                    &dnsforwarders);
03773                         if (result == ISC_R_SUCCESS &&
03774                             dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
03775                                 continue;
03776 
03777                         /*
03778                          * See if we can re-use a existing zone.
03779                          */
03780                         result = dns_viewlist_find(&ns_g_server->viewlist,
03781                                                    view->name, view->rdclass,
03782                                                    &pview);
03783                         if (result != ISC_R_NOTFOUND &&
03784                             result != ISC_R_SUCCESS)
03785                                 goto cleanup;
03786 
03787                         if (pview != NULL) {
03788                                 (void)dns_view_findzone(pview, name, &zone);
03789                                 dns_view_detach(&pview);
03790                         }
03791 
03792                         CHECK(create_empty_zone(zone, name, view, zonelist,
03793                                                 empty_dbtype, empty_dbtypec,
03794                                                 statlevel));
03795                         if (zone != NULL)
03796                                 dns_zone_detach(&zone);
03797                 }
03798         }
03799 
03800         obj = NULL;
03801         result = ns_config_get(maps, "rate-limit", &obj);
03802         if (result == ISC_R_SUCCESS) {
03803                 result = configure_rrl(view, config, obj);
03804                 if (result != ISC_R_SUCCESS)
03805                         goto cleanup;
03806         }
03807 
03808         /*
03809          * Set the servfail-ttl.
03810          */
03811         obj = NULL;
03812         result = ns_config_get(maps, "servfail-ttl", &obj);
03813         INSIST(result == ISC_R_SUCCESS);
03814         fail_ttl  = cfg_obj_asuint32(obj);
03815         if (fail_ttl > 300)
03816                 fail_ttl = 300;
03817         dns_view_setfailttl(view, fail_ttl);
03818 
03819         /*
03820          * Name space to look up redirect information in.
03821          */
03822         obj = NULL;
03823         result = ns_config_get(maps, "nxdomain-redirect", &obj);
03824         if (result == ISC_R_SUCCESS) {
03825                 dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
03826                 CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), 0,
03827                                           NULL));
03828                 view->redirectzone = name;
03829         } else
03830                 view->redirectzone = NULL;
03831 
03832 
03833         result = ISC_R_SUCCESS;
03834 
03835  cleanup:
03836         if (clients != NULL)
03837                 dns_acl_detach(&clients);
03838         if (mapped != NULL)
03839                 dns_acl_detach(&mapped);
03840         if (excluded != NULL)
03841                 dns_acl_detach(&excluded);
03842         if (ring != NULL)
03843                 dns_tsigkeyring_detach(&ring);
03844         if (zone != NULL)
03845                 dns_zone_detach(&zone);
03846         if (dispatch4 != NULL)
03847                 dns_dispatch_detach(&dispatch4);
03848         if (dispatch6 != NULL)
03849                 dns_dispatch_detach(&dispatch6);
03850         if (resstats != NULL)
03851                 isc_stats_detach(&resstats);
03852         if (resquerystats != NULL)
03853                 dns_stats_detach(&resquerystats);
03854         if (order != NULL)
03855                 dns_order_detach(&order);
03856         if (cmctx != NULL)
03857                 isc_mem_detach(&cmctx);
03858         if (hmctx != NULL)
03859                 isc_mem_detach(&hmctx);
03860 
03861         if (cache != NULL)
03862                 dns_cache_detach(&cache);
03863 
03864         return (result);
03865 }
03866 
03867 static isc_result_t
03868 configure_hints(dns_view_t *view, const char *filename) {
03869         isc_result_t result;
03870         dns_db_t *db;
03871 
03872         db = NULL;
03873         result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
03874         if (result == ISC_R_SUCCESS) {
03875                 dns_view_sethints(view, db);
03876                 dns_db_detach(&db);
03877         }
03878 
03879         return (result);
03880 }
03881 
03882 static isc_result_t
03883 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
03884                      const cfg_obj_t *alternates)
03885 {
03886         const cfg_obj_t *portobj;
03887         const cfg_obj_t *addresses;
03888         const cfg_listelt_t *element;
03889         isc_result_t result = ISC_R_SUCCESS;
03890         in_port_t port;
03891 
03892         /*
03893          * Determine which port to send requests to.
03894          */
03895         if (ns_g_lwresdonly && ns_g_port != 0)
03896                 port = ns_g_port;
03897         else
03898                 CHECKM(ns_config_getport(config, &port), "port");
03899 
03900         if (alternates != NULL) {
03901                 portobj = cfg_tuple_get(alternates, "port");
03902                 if (cfg_obj_isuint32(portobj)) {
03903                         isc_uint32_t val = cfg_obj_asuint32(portobj);
03904                         if (val > ISC_UINT16_MAX) {
03905                                 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
03906                                             "port '%u' out of range", val);
03907                                 return (ISC_R_RANGE);
03908                         }
03909                         port = (in_port_t) val;
03910                 }
03911         }
03912 
03913         addresses = NULL;
03914         if (alternates != NULL)
03915                 addresses = cfg_tuple_get(alternates, "addresses");
03916 
03917         for (element = cfg_list_first(addresses);
03918              element != NULL;
03919              element = cfg_list_next(element))
03920         {
03921                 const cfg_obj_t *alternate = cfg_listelt_value(element);
03922                 isc_sockaddr_t sa;
03923 
03924                 if (!cfg_obj_issockaddr(alternate)) {
03925                         dns_fixedname_t fixed;
03926                         dns_name_t *name;
03927                         const char *str = cfg_obj_asstring(cfg_tuple_get(
03928                                                            alternate, "name"));
03929                         isc_buffer_t buffer;
03930                         in_port_t myport = port;
03931 
03932                         isc_buffer_constinit(&buffer, str, strlen(str));
03933                         isc_buffer_add(&buffer, strlen(str));
03934                         dns_fixedname_init(&fixed);
03935                         name = dns_fixedname_name(&fixed);
03936                         CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
03937                                                 NULL));
03938 
03939                         portobj = cfg_tuple_get(alternate, "port");
03940                         if (cfg_obj_isuint32(portobj)) {
03941                                 isc_uint32_t val = cfg_obj_asuint32(portobj);
03942                                 if (val > ISC_UINT16_MAX) {
03943                                         cfg_obj_log(portobj, ns_g_lctx,
03944                                                     ISC_LOG_ERROR,
03945                                                     "port '%u' out of range",
03946                                                      val);
03947                                         return (ISC_R_RANGE);
03948                                 }
03949                                 myport = (in_port_t) val;
03950                         }
03951                         CHECK(dns_resolver_addalternate(view->resolver, NULL,
03952                                                         name, myport));
03953                         continue;
03954                 }
03955 
03956                 sa = *cfg_obj_assockaddr(alternate);
03957                 if (isc_sockaddr_getport(&sa) == 0)
03958                         isc_sockaddr_setport(&sa, port);
03959                 CHECK(dns_resolver_addalternate(view->resolver, &sa,
03960                                                 NULL, 0));
03961         }
03962 
03963  cleanup:
03964         return (result);
03965 }
03966 
03967 static isc_result_t
03968 configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
03969                   const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype)
03970 {
03971         const cfg_obj_t *portobj, *dscpobj;
03972         const cfg_obj_t *faddresses;
03973         const cfg_listelt_t *element;
03974         dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
03975         dns_forwarderlist_t fwdlist;
03976         dns_forwarder_t *fwd;
03977         isc_result_t result;
03978         in_port_t port;
03979         isc_dscp_t dscp = -1;
03980 
03981         ISC_LIST_INIT(fwdlist);
03982 
03983         /*
03984          * Determine which port to send forwarded requests to.
03985          */
03986         if (ns_g_lwresdonly && ns_g_port != 0)
03987                 port = ns_g_port;
03988         else
03989                 CHECKM(ns_config_getport(config, &port), "port");
03990 
03991         if (forwarders != NULL) {
03992                 portobj = cfg_tuple_get(forwarders, "port");
03993                 if (cfg_obj_isuint32(portobj)) {
03994                         isc_uint32_t val = cfg_obj_asuint32(portobj);
03995                         if (val > ISC_UINT16_MAX) {
03996                                 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
03997                                             "port '%u' out of range", val);
03998                                 return (ISC_R_RANGE);
03999                         }
04000                         port = (in_port_t) val;
04001                 }
04002         }
04003 
04004         /*
04005          * DSCP value for forwarded requests.
04006          */
04007         dscp = ns_g_dscp;
04008         if (forwarders != NULL) {
04009                 dscpobj = cfg_tuple_get(forwarders, "dscp");
04010                 if (cfg_obj_isuint32(dscpobj)) {
04011                         if (cfg_obj_asuint32(dscpobj) > 63) {
04012                                 cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR,
04013                                             "dscp value '%u' is out of range",
04014                                             cfg_obj_asuint32(dscpobj));
04015                                 return (ISC_R_RANGE);
04016                         }
04017                         dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
04018                 }
04019         }
04020 
04021         faddresses = NULL;
04022         if (forwarders != NULL)
04023                 faddresses = cfg_tuple_get(forwarders, "addresses");
04024 
04025         for (element = cfg_list_first(faddresses);
04026              element != NULL;
04027              element = cfg_list_next(element))
04028         {
04029                 const cfg_obj_t *forwarder = cfg_listelt_value(element);
04030                 fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
04031                 if (fwd == NULL) {
04032                         result = ISC_R_NOMEMORY;
04033                         goto cleanup;
04034                 }
04035                 fwd->addr = *cfg_obj_assockaddr(forwarder);
04036                 if (isc_sockaddr_getport(&fwd->addr) == 0)
04037                         isc_sockaddr_setport(&fwd->addr, port);
04038                 fwd->dscp = cfg_obj_getdscp(forwarder);
04039                 if (fwd->dscp == -1)
04040                         fwd->dscp = dscp;
04041                 ISC_LINK_INIT(fwd, link);
04042                 ISC_LIST_APPEND(fwdlist, fwd, link);
04043         }
04044 
04045         if (ISC_LIST_EMPTY(fwdlist)) {
04046                 if (forwardtype != NULL)
04047                         cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
04048                                     "no forwarders seen; disabling "
04049                                     "forwarding");
04050                 fwdpolicy = dns_fwdpolicy_none;
04051         } else {
04052                 if (forwardtype == NULL)
04053                         fwdpolicy = dns_fwdpolicy_first;
04054                 else {
04055                         const char *forwardstr = cfg_obj_asstring(forwardtype);
04056                         if (strcasecmp(forwardstr, "first") == 0)
04057                                 fwdpolicy = dns_fwdpolicy_first;
04058                         else if (strcasecmp(forwardstr, "only") == 0)
04059                                 fwdpolicy = dns_fwdpolicy_only;
04060                         else
04061                                 INSIST(0);
04062                 }
04063         }
04064 
04065         result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
04066                                      fwdpolicy);
04067         if (result != ISC_R_SUCCESS) {
04068                 char namebuf[DNS_NAME_FORMATSIZE];
04069                 dns_name_format(origin, namebuf, sizeof(namebuf));
04070                 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
04071                             "could not set up forwarding for domain '%s': %s",
04072                             namebuf, isc_result_totext(result));
04073                 goto cleanup;
04074         }
04075 
04076         result = ISC_R_SUCCESS;
04077 
04078  cleanup:
04079 
04080         while (!ISC_LIST_EMPTY(fwdlist)) {
04081                 fwd = ISC_LIST_HEAD(fwdlist);
04082                 ISC_LIST_UNLINK(fwdlist, fwd, link);
04083                 isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
04084         }
04085 
04086         return (result);
04087 }
04088 
04089 static isc_result_t
04090 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
04091              dns_rdataclass_t *classp)
04092 {
04093         isc_result_t result = ISC_R_SUCCESS;
04094         const char *viewname;
04095         dns_rdataclass_t viewclass;
04096 
04097         REQUIRE(namep != NULL && *namep == NULL);
04098         REQUIRE(classp != NULL);
04099 
04100         if (vconfig != NULL) {
04101                 const cfg_obj_t *classobj = NULL;
04102 
04103                 viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
04104                 classobj = cfg_tuple_get(vconfig, "class");
04105                 result = ns_config_getclass(classobj, dns_rdataclass_in,
04106                                             &viewclass);
04107         } else {
04108                 viewname = "_default";
04109                 viewclass = dns_rdataclass_in;
04110         }
04111 
04112         *namep = viewname;
04113         *classp = viewclass;
04114 
04115         return (result);
04116 }
04117 
04118 /*
04119  * Find a view based on its configuration info and attach to it.
04120  *
04121  * If 'vconfig' is NULL, attach to the default view.
04122  */
04123 static isc_result_t
04124 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
04125           dns_view_t **viewp)
04126 {
04127         isc_result_t result;
04128         const char *viewname = NULL;
04129         dns_rdataclass_t viewclass;
04130         dns_view_t *view = NULL;
04131 
04132         result = get_viewinfo(vconfig, &viewname, &viewclass);
04133         if (result != ISC_R_SUCCESS)
04134                 return (result);
04135 
04136         result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
04137         if (result != ISC_R_SUCCESS)
04138                 return (result);
04139 
04140         *viewp = view;
04141         return (ISC_R_SUCCESS);
04142 }
04143 
04144 /*
04145  * Create a new view and add it to the list.
04146  *
04147  * If 'vconfig' is NULL, create the default view.
04148  *
04149  * The view created is attached to '*viewp'.
04150  */
04151 static isc_result_t
04152 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
04153             dns_view_t **viewp)
04154 {
04155         isc_result_t result;
04156         const char *viewname = NULL;
04157         dns_rdataclass_t viewclass;
04158         dns_view_t *view = NULL;
04159 
04160         result = get_viewinfo(vconfig, &viewname, &viewclass);
04161         if (result != ISC_R_SUCCESS)
04162                 return (result);
04163 
04164         result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
04165         if (result == ISC_R_SUCCESS)
04166                 return (ISC_R_EXISTS);
04167         if (result != ISC_R_NOTFOUND)
04168                 return (result);
04169         INSIST(view == NULL);
04170 
04171         result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
04172         if (result != ISC_R_SUCCESS)
04173                 return (result);
04174 
04175         result = isc_entropy_getdata(ns_g_entropy, view->secret,
04176                                      sizeof(view->secret), NULL, 0);
04177         if (result != ISC_R_SUCCESS) {
04178                 dns_view_detach(&view);
04179                 return (result);
04180         }
04181 
04182 #ifdef HAVE_GEOIP
04183         view->aclenv.geoip = ns_g_geoip;
04184 #endif
04185 
04186         ISC_LIST_APPEND(*viewlist, view, link);
04187         dns_view_attach(view, viewp);
04188         return (ISC_R_SUCCESS);
04189 }
04190 
04191 /*
04192  * Configure or reconfigure a zone.
04193  */
04194 static isc_result_t
04195 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
04196                const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
04197                dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
04198                isc_boolean_t added, isc_boolean_t old_rpz_ok,
04199                isc_boolean_t modify)
04200 {
04201         dns_view_t *pview = NULL;       /* Production view */
04202         dns_zone_t *zone = NULL;        /* New or reused zone */
04203         dns_zone_t *raw = NULL;         /* New or reused raw zone */
04204         dns_zone_t *dupzone = NULL;
04205         const cfg_obj_t *options = NULL;
04206         const cfg_obj_t *zoptions = NULL;
04207         const cfg_obj_t *typeobj = NULL;
04208         const cfg_obj_t *forwarders = NULL;
04209         const cfg_obj_t *forwardtype = NULL;
04210         const cfg_obj_t *only = NULL;
04211         const cfg_obj_t *signing = NULL;
04212         const cfg_obj_t *viewobj = NULL;
04213         isc_result_t result;
04214         isc_result_t tresult;
04215         isc_buffer_t buffer;
04216         dns_fixedname_t fixorigin;
04217         dns_name_t *origin;
04218         const char *zname;
04219         dns_rdataclass_t zclass;
04220         const char *ztypestr;
04221         dns_rpz_num_t rpz_num;
04222 
04223         options = NULL;
04224         (void)cfg_map_get(config, "options", &options);
04225 
04226         zoptions = cfg_tuple_get(zconfig, "options");
04227 
04228         /*
04229          * Get the zone origin as a dns_name_t.
04230          */
04231         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
04232         isc_buffer_constinit(&buffer, zname, strlen(zname));
04233         isc_buffer_add(&buffer, strlen(zname));
04234         dns_fixedname_init(&fixorigin);
04235         CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
04236                                 &buffer, dns_rootname, 0, NULL));
04237         origin = dns_fixedname_name(&fixorigin);
04238 
04239         CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
04240                                  view->rdclass, &zclass));
04241         if (zclass != view->rdclass) {
04242                 const char *vname = NULL;
04243                 if (vconfig != NULL)
04244                         vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
04245                                                                "name"));
04246                 else
04247                         vname = "<default view>";
04248 
04249                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04250                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
04251                               "zone '%s': wrong class for view '%s'",
04252                               zname, vname);
04253                 result = ISC_R_FAILURE;
04254                 goto cleanup;
04255         }
04256 
04257         (void)cfg_map_get(zoptions, "in-view", &viewobj);
04258         if (viewobj != NULL) {
04259                 const char *inview = cfg_obj_asstring(viewobj);
04260                 dns_view_t *otherview = NULL;
04261 
04262                 if (viewlist == NULL) {
04263                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04264                                     "'in-view' option is not permitted in "
04265                                     "dynamically added zones");
04266                         result = ISC_R_FAILURE;
04267                         goto cleanup;
04268                 }
04269 
04270                 result = dns_viewlist_find(viewlist, inview, view->rdclass,
04271                                            &otherview);
04272                 if (result != ISC_R_SUCCESS) {
04273                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04274                                     "view '%s' is not yet defined.", inview);
04275                         result = ISC_R_FAILURE;
04276                         goto cleanup;
04277                 }
04278 
04279                 result = dns_view_findzone(otherview, origin, &zone);
04280                 dns_view_detach(&otherview);
04281                 if (result != ISC_R_SUCCESS) {
04282                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04283                                     "zone '%s' not defined in view '%s'",
04284                                     zname, inview);
04285                         result = ISC_R_FAILURE;
04286                         goto cleanup;
04287                 }
04288 
04289                 CHECK(dns_view_addzone(view, zone));
04290                 dns_zone_detach(&zone);
04291 
04292                 /*
04293                  * If the zone contains a 'forwarders' statement, configure
04294                  * selective forwarding.  Note: this is not inherited from the
04295                  * other view.
04296                  */
04297                 forwarders = NULL;
04298                 result = cfg_map_get(zoptions, "forwarders", &forwarders);
04299                 if (result == ISC_R_SUCCESS) {
04300                         forwardtype = NULL;
04301                         (void)cfg_map_get(zoptions, "forward", &forwardtype);
04302                         CHECK(configure_forward(config, view, origin,
04303                                                 forwarders, forwardtype));
04304                 }
04305                 result = ISC_R_SUCCESS;
04306                 goto cleanup;
04307         }
04308 
04309         (void)cfg_map_get(zoptions, "type", &typeobj);
04310         if (typeobj == NULL) {
04311                 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04312                             "zone '%s' 'type' not specified", zname);
04313                 result = ISC_R_FAILURE;
04314                 goto cleanup;
04315         }
04316         ztypestr = cfg_obj_asstring(typeobj);
04317 
04318         /*
04319          * "hints zones" aren't zones.  If we've got one,
04320          * configure it and return.
04321          */
04322         if (strcasecmp(ztypestr, "hint") == 0) {
04323                 const cfg_obj_t *fileobj = NULL;
04324                 if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
04325                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04326                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
04327                                       "zone '%s': 'file' not specified",
04328                                       zname);
04329                         result = ISC_R_FAILURE;
04330                         goto cleanup;
04331                 }
04332                 if (dns_name_equal(origin, dns_rootname)) {
04333                         const char *hintsfile = cfg_obj_asstring(fileobj);
04334 
04335                         CHECK(configure_hints(view, hintsfile));
04336 
04337                         /*
04338                          * Hint zones may also refer to delegation only points.
04339                          */
04340                         only = NULL;
04341                         tresult = cfg_map_get(zoptions, "delegation-only",
04342                                               &only);
04343                         if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
04344                                 CHECK(dns_view_adddelegationonly(view, origin));
04345                 } else {
04346                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04347                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
04348                                       "ignoring non-root hint zone '%s'",
04349                                       zname);
04350                         result = ISC_R_SUCCESS;
04351                 }
04352                 /* Skip ordinary zone processing. */
04353                 goto cleanup;
04354         }
04355 
04356         /*
04357          * "forward zones" aren't zones either.  Translate this syntax into
04358          * the appropriate selective forwarding configuration and return.
04359          */
04360         if (strcasecmp(ztypestr, "forward") == 0) {
04361                 forwardtype = NULL;
04362                 forwarders = NULL;
04363 
04364                 (void)cfg_map_get(zoptions, "forward", &forwardtype);
04365                 (void)cfg_map_get(zoptions, "forwarders", &forwarders);
04366                 CHECK(configure_forward(config, view, origin, forwarders,
04367                                         forwardtype));
04368 
04369                 /*
04370                  * Forward zones may also set delegation only.
04371                  */
04372                 only = NULL;
04373                 tresult = cfg_map_get(zoptions, "delegation-only", &only);
04374                 if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
04375                         CHECK(dns_view_adddelegationonly(view, origin));
04376                 goto cleanup;
04377         }
04378 
04379         /*
04380          * "delegation-only zones" aren't zones either.
04381          */
04382         if (strcasecmp(ztypestr, "delegation-only") == 0) {
04383                 result = dns_view_adddelegationonly(view, origin);
04384                 goto cleanup;
04385         }
04386 
04387         /*
04388          * Redirect zones only require minimal configuration.
04389          */
04390         if (strcasecmp(ztypestr, "redirect") == 0) {
04391                 if (view->redirect != NULL) {
04392                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04393                                     "redirect zone already exists");
04394                         result = ISC_R_EXISTS;
04395                         goto cleanup;
04396                 }
04397                 result = dns_viewlist_find(viewlist, view->name,
04398                                            view->rdclass, &pview);
04399                 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
04400                         goto cleanup;
04401                 if (pview != NULL && pview->redirect != NULL) {
04402                         dns_zone_attach(pview->redirect, &zone);
04403                         dns_zone_setview(zone, view);
04404                 } else {
04405                         CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr,
04406                                                      &zone));
04407                         CHECK(dns_zone_setorigin(zone, origin));
04408                         dns_zone_setview(zone, view);
04409                         CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
04410                                                      zone));
04411                         dns_zone_setstats(zone, ns_g_server->zonestats);
04412                 }
04413                 CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf,
04414                                         zone, NULL));
04415                 dns_zone_attach(zone, &view->redirect);
04416                 goto cleanup;
04417         }
04418 
04419         if (!modify) {
04420                 /*
04421                  * Check for duplicates in the new zone table.
04422                  */
04423                 result = dns_view_findzone(view, origin, &dupzone);
04424                 if (result == ISC_R_SUCCESS) {
04425                         /*
04426                          * We already have this zone!
04427                          */
04428                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04429                                     "zone '%s' already exists", zname);
04430                         dns_zone_detach(&dupzone);
04431                         result = ISC_R_EXISTS;
04432                         goto cleanup;
04433                 }
04434                 INSIST(dupzone == NULL);
04435         }
04436 
04437         /*
04438          * Note whether this is a response policy zone and which one if so.
04439          */
04440         for (rpz_num = 0; ; ++rpz_num) {
04441                 if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones) {
04442                         rpz_num = DNS_RPZ_INVALID_NUM;
04443                         break;
04444                 }
04445                 if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
04446                         break;
04447         }
04448 
04449         /*
04450          * See if we can reuse an existing zone.  This is
04451          * only possible if all of these are true:
04452          *   - The zone's view exists
04453          *   - A zone with the right name exists in the view
04454          *   - The zone is compatible with the config
04455          *     options (e.g., an existing master zone cannot
04456          *     be reused if the options specify a slave zone)
04457          *   - The zone was not and is still not a response policy zone
04458          *     or the zone is a policy zone with an unchanged number
04459          *     and we are using the old policy zone summary data.
04460          */
04461         result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
04462                                    view->rdclass, &pview);
04463         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
04464                 goto cleanup;
04465         if (pview != NULL)
04466                 result = dns_view_findzone(pview, origin, &zone);
04467         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
04468                 goto cleanup;
04469 
04470         if (zone != NULL && !ns_zone_reusable(zone, zconfig))
04471                 dns_zone_detach(&zone);
04472 
04473         if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
04474                              (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
04475                 dns_zone_detach(&zone);
04476 
04477         if (zone != NULL) {
04478                 /*
04479                  * We found a reusable zone.  Make it use the
04480                  * new view.
04481                  */
04482                 dns_zone_setview(zone, view);
04483                 if (view->acache != NULL)
04484                         dns_zone_setacache(zone, view->acache);
04485         } else {
04486                 /*
04487                  * We cannot reuse an existing zone, we have
04488                  * to create a new one.
04489                  */
04490                 CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
04491                 CHECK(dns_zone_setorigin(zone, origin));
04492                 dns_zone_setview(zone, view);
04493                 if (view->acache != NULL)
04494                         dns_zone_setacache(zone, view->acache);
04495                 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
04496                 dns_zone_setstats(zone, ns_g_server->zonestats);
04497         }
04498 
04499         if (rpz_num != DNS_RPZ_INVALID_NUM) {
04500                 result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
04501                 if (result != ISC_R_SUCCESS) {
04502                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04503                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
04504                                       "zone '%s': incompatible"
04505                                       " masterfile-format or database"
04506                                       " for a response policy zone",
04507                                       zname);
04508                         goto cleanup;
04509                 }
04510         }
04511 
04512         /*
04513          * If the zone contains a 'forwarders' statement, configure
04514          * selective forwarding.
04515          */
04516         forwarders = NULL;
04517         if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
04518         {
04519                 forwardtype = NULL;
04520                 (void)cfg_map_get(zoptions, "forward", &forwardtype);
04521                 CHECK(configure_forward(config, view, origin, forwarders,
04522                                         forwardtype));
04523         }
04524 
04525         /*
04526          * Stub and forward zones may also refer to delegation only points.
04527          */
04528         only = NULL;
04529         if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
04530         {
04531                 if (cfg_obj_asboolean(only))
04532                         CHECK(dns_view_adddelegationonly(view, origin));
04533         }
04534 
04535         /*
04536          * Mark whether the zone was originally added at runtime or not
04537          */
04538         dns_zone_setadded(zone, added);
04539 
04540         signing = NULL;
04541         if ((strcasecmp(ztypestr, "master") == 0 ||
04542              strcasecmp(ztypestr, "slave") == 0) &&
04543             cfg_map_get(zoptions, "inline-signing", &signing) == ISC_R_SUCCESS &&
04544             cfg_obj_asboolean(signing))
04545         {
04546                 dns_zone_getraw(zone, &raw);
04547                 if (raw == NULL) {
04548                         CHECK(dns_zone_create(&raw, mctx));
04549                         CHECK(dns_zone_setorigin(raw, origin));
04550                         dns_zone_setview(raw, view);
04551                         if (view->acache != NULL)
04552                                 dns_zone_setacache(raw, view->acache);
04553                         dns_zone_setstats(raw, ns_g_server->zonestats);
04554                         CHECK(dns_zone_link(zone, raw));
04555                 }
04556         }
04557 
04558         /*
04559          * Configure the zone.
04560          */
04561         CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone, raw));
04562 
04563         /*
04564          * Add the zone to its view in the new view list.
04565          */
04566         if (!modify)
04567                 CHECK(dns_view_addzone(view, zone));
04568 
04569         /*
04570          * Ensure that zone keys are reloaded on reconfig
04571          */
04572         if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0)
04573                 dns_zone_rekey(zone, ISC_FALSE);
04574 
04575  cleanup:
04576         if (zone != NULL)
04577                 dns_zone_detach(&zone);
04578         if (raw != NULL)
04579                 dns_zone_detach(&raw);
04580         if (pview != NULL)
04581                 dns_view_detach(&pview);
04582 
04583         return (result);
04584 }
04585 
04586 /*
04587  * Configure built-in zone for storing managed-key data.
04588  */
04589 
04590 static isc_result_t
04591 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
04592         isc_result_t result;
04593         dns_view_t *pview = NULL;
04594         dns_zone_t *zone = NULL;
04595         dns_acl_t *none = NULL;
04596         char filename[PATH_MAX];
04597         isc_boolean_t defaultview;
04598 
04599         REQUIRE(view != NULL);
04600 
04601         /* See if we can re-use an existing keydata zone. */
04602         result = dns_viewlist_find(&ns_g_server->viewlist,
04603                                    view->name, view->rdclass,
04604                                    &pview);
04605         if (result != ISC_R_NOTFOUND &&
04606             result != ISC_R_SUCCESS)
04607                 return (result);
04608 
04609         if (pview != NULL && pview->managed_keys != NULL) {
04610                 dns_zone_attach(pview->managed_keys, &view->managed_keys);
04611                 dns_zone_setview(pview->managed_keys, view);
04612                 dns_view_detach(&pview);
04613                 dns_zone_synckeyzone(view->managed_keys);
04614                 return (ISC_R_SUCCESS);
04615         }
04616 
04617         /* No existing keydata zone was found; create one */
04618         CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
04619         CHECK(dns_zone_setorigin(zone, dns_rootname));
04620 
04621         defaultview = ISC_TF(strcmp(view->name, "_default") == 0);
04622         CHECK(isc_file_sanitize(directory,
04623                                 defaultview ? "managed-keys" : view->name,
04624                                 defaultview ? "bind" : "mkeys",
04625                                 filename, sizeof(filename)));
04626         CHECK(dns_zone_setfile(zone, filename));
04627 
04628         dns_zone_setview(zone, view);
04629         dns_zone_settype(zone, dns_zone_key);
04630         dns_zone_setclass(zone, view->rdclass);
04631 
04632         CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
04633 
04634         if (view->acache != NULL)
04635                 dns_zone_setacache(zone, view->acache);
04636 
04637         CHECK(dns_acl_none(mctx, &none));
04638         dns_zone_setqueryacl(zone, none);
04639         dns_zone_setqueryonacl(zone, none);
04640         dns_acl_detach(&none);
04641 
04642         dns_zone_setdialup(zone, dns_dialuptype_no);
04643         dns_zone_setnotifytype(zone, dns_notifytype_no);
04644         dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
04645         dns_zone_setjournalsize(zone, 0);
04646 
04647         dns_zone_setstats(zone, ns_g_server->zonestats);
04648         CHECK(setquerystats(zone, mctx, dns_zonestat_none));
04649 
04650         if (view->managed_keys != NULL)
04651                 dns_zone_detach(&view->managed_keys);
04652         dns_zone_attach(zone, &view->managed_keys);
04653 
04654         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04655                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
04656                       "set up managed keys zone for view %s, file '%s'",
04657                       view->name, filename);
04658 
04659 cleanup:
04660         if (zone != NULL)
04661                 dns_zone_detach(&zone);
04662         if (none != NULL)
04663                 dns_acl_detach(&none);
04664 
04665         return (result);
04666 }
04667 
04668 /*
04669  * Configure a single server quota.
04670  */
04671 static void
04672 configure_server_quota(const cfg_obj_t **maps, const char *name,
04673                        isc_quota_t *quota)
04674 {
04675         const cfg_obj_t *obj = NULL;
04676         isc_result_t result;
04677 
04678         result = ns_config_get(maps, name, &obj);
04679         INSIST(result == ISC_R_SUCCESS);
04680         isc_quota_max(quota, cfg_obj_asuint32(obj));
04681 }
04682 
04683 /*
04684  * This function is called as soon as the 'directory' statement has been
04685  * parsed.  This can be extended to support other options if necessary.
04686  */
04687 static isc_result_t
04688 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
04689         isc_result_t result;
04690         const char *directory;
04691 
04692         REQUIRE(strcasecmp("directory", clausename) == 0);
04693 
04694         UNUSED(arg);
04695         UNUSED(clausename);
04696 
04697         /*
04698          * Change directory.
04699          */
04700         directory = cfg_obj_asstring(obj);
04701 
04702         if (! isc_file_ischdiridempotent(directory))
04703                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
04704                             "option 'directory' contains relative path '%s'",
04705                             directory);
04706 
04707         result = isc_dir_chdir(directory);
04708         if (result != ISC_R_SUCCESS) {
04709                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
04710                             "change directory to '%s' failed: %s",
04711                             directory, isc_result_totext(result));
04712                 return (result);
04713         }
04714 
04715         return (ISC_R_SUCCESS);
04716 }
04717 
04718 static isc_result_t
04719 scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
04720         isc_result_t result;
04721         isc_boolean_t match_mapped = server->aclenv.match_mapped;
04722 #ifdef HAVE_GEOIP
04723         isc_boolean_t use_ecs = server->aclenv.geoip_use_ecs;
04724 #endif
04725 
04726         result = ns_interfacemgr_scan(server->interfacemgr, verbose);
04727         /*
04728          * Update the "localhost" and "localnets" ACLs to match the
04729          * current set of network interfaces.
04730          */
04731         dns_aclenv_copy(&server->aclenv,
04732                         ns_interfacemgr_getaclenv(server->interfacemgr));
04733 
04734         server->aclenv.match_mapped = match_mapped;
04735 #ifdef HAVE_GEOIP
04736         server->aclenv.geoip_use_ecs = use_ecs;
04737 #endif
04738 
04739         return (result);
04740 }
04741 
04742 static isc_result_t
04743 add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
04744               isc_dscp_t dscp, isc_boolean_t wcardport_ok)
04745 {
04746         ns_listenelt_t *lelt = NULL;
04747         dns_acl_t *src_acl = NULL;
04748         isc_result_t result;
04749         isc_sockaddr_t any_sa6;
04750         isc_netaddr_t netaddr;
04751 
04752         REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
04753 
04754         isc_sockaddr_any6(&any_sa6);
04755         if (!isc_sockaddr_equal(&any_sa6, addr) &&
04756             (wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
04757                 isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr);
04758 
04759                 result = dns_acl_create(mctx, 0, &src_acl);
04760                 if (result != ISC_R_SUCCESS)
04761                         return (result);
04762 
04763                 result = dns_iptable_addprefix(src_acl->iptable,
04764                                                &netaddr, 128, ISC_TRUE);
04765                 if (result != ISC_R_SUCCESS)
04766                         goto clean;
04767 
04768                 result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
04769                                              dscp, src_acl, &lelt);
04770                 if (result != ISC_R_SUCCESS)
04771                         goto clean;
04772                 ISC_LIST_APPEND(list->elts, lelt, link);
04773         }
04774 
04775         return (ISC_R_SUCCESS);
04776 
04777  clean:
04778         INSIST(lelt == NULL);
04779         dns_acl_detach(&src_acl);
04780 
04781         return (result);
04782 }
04783 
04784 /*
04785  * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
04786  * to update the listening interfaces accordingly.
04787  * We currently only consider IPv6, because this only affects IPv6 wildcard
04788  * sockets.
04789  */
04790 static void
04791 adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
04792         isc_result_t result;
04793         ns_listenlist_t *list = NULL;
04794         dns_view_t *view;
04795         dns_zone_t *zone, *next;
04796         isc_sockaddr_t addr, *addrp;
04797         isc_dscp_t dscp = -1;
04798 
04799         result = ns_listenlist_create(mctx, &list);
04800         if (result != ISC_R_SUCCESS)
04801                 return;
04802 
04803         for (view = ISC_LIST_HEAD(server->viewlist);
04804              view != NULL;
04805              view = ISC_LIST_NEXT(view, link)) {
04806                 dns_dispatch_t *dispatch6;
04807 
04808                 dispatch6 = dns_resolver_dispatchv6(view->resolver);
04809                 if (dispatch6 == NULL)
04810                         continue;
04811                 result = dns_dispatch_getlocaladdress(dispatch6, &addr);
04812                 if (result != ISC_R_SUCCESS)
04813                         goto fail;
04814 
04815                 /*
04816                  * We always add non-wildcard address regardless of whether
04817                  * the port is 'any' (the fourth arg is TRUE): if the port is
04818                  * specific, we need to add it since it may conflict with a
04819                  * listening interface; if it's zero, we'll dynamically open
04820                  * query ports, and some of them may override an existing
04821                  * wildcard IPv6 port.
04822                  */
04823                 /* XXXMPA fix dscp */
04824                 result = add_listenelt(mctx, list, &addr, dscp, ISC_TRUE);
04825                 if (result != ISC_R_SUCCESS)
04826                         goto fail;
04827         }
04828 
04829         zone = NULL;
04830         for (result = dns_zone_first(server->zonemgr, &zone);
04831              result == ISC_R_SUCCESS;
04832              next = NULL, result = dns_zone_next(zone, &next), zone = next) {
04833                 dns_view_t *zoneview;
04834 
04835                 /*
04836                  * At this point the zone list may contain a stale zone
04837                  * just removed from the configuration.  To see the validity,
04838                  * check if the corresponding view is in our current view list.
04839                  * There may also be old zones that are still in the process
04840                  * of shutting down and have detached from their old view
04841                  * (zoneview == NULL).
04842                  */
04843                 zoneview = dns_zone_getview(zone);
04844                 if (zoneview == NULL)
04845                         continue;
04846                 for (view = ISC_LIST_HEAD(server->viewlist);
04847                      view != NULL && view != zoneview;
04848                      view = ISC_LIST_NEXT(view, link))
04849                         ;
04850                 if (view == NULL)
04851                         continue;
04852 
04853                 addrp = dns_zone_getnotifysrc6(zone);
04854                 dscp = dns_zone_getnotifysrc6dscp(zone);
04855                 result = add_listenelt(mctx, list, addrp, dscp, ISC_FALSE);
04856                 if (result != ISC_R_SUCCESS)
04857                         goto fail;
04858 
04859                 addrp = dns_zone_getxfrsource6(zone);
04860                 dscp = dns_zone_getxfrsource6dscp(zone);
04861                 result = add_listenelt(mctx, list, addrp, dscp, ISC_FALSE);
04862                 if (result != ISC_R_SUCCESS)
04863                         goto fail;
04864         }
04865 
04866         ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
04867 
04868  clean:
04869         ns_listenlist_detach(&list);
04870         return;
04871 
04872  fail:
04873         /*
04874          * Even when we failed the procedure, most of other interfaces
04875          * should work correctly.  We therefore just warn it.
04876          */
04877         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04878                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
04879                       "could not adjust the listen-on list; "
04880                       "some interfaces may not work");
04881         goto clean;
04882 }
04883 
04884 /*
04885  * This event callback is invoked to do periodic network interface
04886  * scanning.  It is also called by ns_server_scan_interfaces(),
04887  * invoked by "rndc scan"
04888  */
04889 
04890 static void
04891 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
04892         isc_result_t result;
04893         ns_server_t *server = (ns_server_t *) event->ev_arg;
04894         INSIST(task == server->task);
04895         UNUSED(task);
04896 
04897         isc_event_free(&event);
04898 
04899         /*
04900          * XXX should scan interfaces unlocked and get exclusive access
04901          * only to replace ACLs.
04902          */
04903         result = isc_task_beginexclusive(server->task);
04904         RUNTIME_CHECK(result == ISC_R_SUCCESS);
04905         scan_interfaces(server, ISC_FALSE);
04906         isc_task_endexclusive(server->task);
04907 }
04908 
04909 static void
04910 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
04911         ns_server_t *server = (ns_server_t *) event->ev_arg;
04912         dns_view_t *view;
04913 
04914         UNUSED(task);
04915         isc_event_free(&event);
04916         view = ISC_LIST_HEAD(server->viewlist);
04917         while (view != NULL) {
04918                 dns_view_dialup(view);
04919                 view = ISC_LIST_NEXT(view, link);
04920         }
04921 }
04922 
04923 static void
04924 pps_timer_tick(isc_task_t *task, isc_event_t *event) {
04925         static unsigned int oldrequests = 0;
04926         unsigned int requests = ns_client_requests;
04927 
04928         UNUSED(task);
04929         isc_event_free(&event);
04930 
04931         /*
04932          * Don't worry about wrapping as the overflow result will be right.
04933          */
04934         dns_pps = (requests - oldrequests) / 1200;
04935         oldrequests = requests;
04936 }
04937 
04938 /*
04939  * Replace the current value of '*field', a dynamically allocated
04940  * string or NULL, with a dynamically allocated copy of the
04941  * null-terminated string pointed to by 'value', or NULL.
04942  */
04943 static isc_result_t
04944 setstring(ns_server_t *server, char **field, const char *value) {
04945         char *copy;
04946 
04947         if (value != NULL) {
04948                 copy = isc_mem_strdup(server->mctx, value);
04949                 if (copy == NULL)
04950                         return (ISC_R_NOMEMORY);
04951         } else {
04952                 copy = NULL;
04953         }
04954 
04955         if (*field != NULL)
04956                 isc_mem_free(server->mctx, *field);
04957 
04958         *field = copy;
04959         return (ISC_R_SUCCESS);
04960 }
04961 
04962 /*
04963  * Replace the current value of '*field', a dynamically allocated
04964  * string or NULL, with another dynamically allocated string
04965  * or NULL if whether 'obj' is a string or void value, respectively.
04966  */
04967 static isc_result_t
04968 setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) {
04969         if (cfg_obj_isvoid(obj))
04970                 return (setstring(server, field, NULL));
04971         else
04972                 return (setstring(server, field, cfg_obj_asstring(obj)));
04973 }
04974 
04975 static void
04976 set_limit(const cfg_obj_t **maps, const char *configname,
04977           const char *description, isc_resource_t resourceid,
04978           isc_resourcevalue_t defaultvalue)
04979 {
04980         const cfg_obj_t *obj = NULL;
04981         const char *resource;
04982         isc_resourcevalue_t value;
04983         isc_result_t result;
04984 
04985         if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
04986                 return;
04987 
04988         if (cfg_obj_isstring(obj)) {
04989                 resource = cfg_obj_asstring(obj);
04990                 if (strcasecmp(resource, "unlimited") == 0)
04991                         value = ISC_RESOURCE_UNLIMITED;
04992                 else {
04993                         INSIST(strcasecmp(resource, "default") == 0);
04994                         value = defaultvalue;
04995                 }
04996         } else
04997                 value = cfg_obj_asuint64(obj);
04998 
04999         result = isc_resource_setlimit(resourceid, value);
05000         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
05001                       result == ISC_R_SUCCESS ?
05002                         ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
05003                       "set maximum %s to %" ISC_PRINT_QUADFORMAT "u: %s",
05004                       description, value, isc_result_totext(result));
05005 }
05006 
05007 #define SETLIMIT(cfgvar, resource, description) \
05008         set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
05009                   ns_g_init ## resource)
05010 
05011 static void
05012 set_limits(const cfg_obj_t **maps) {
05013         SETLIMIT("stacksize", stacksize, "stack size");
05014         SETLIMIT("datasize", datasize, "data size");
05015         SETLIMIT("coresize", coresize, "core size");
05016         SETLIMIT("files", openfiles, "open files");
05017 }
05018 
05019 static void
05020 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
05021                  isc_boolean_t positive)
05022 {
05023         const cfg_listelt_t *element;
05024 
05025         for (element = cfg_list_first(ports);
05026              element != NULL;
05027              element = cfg_list_next(element)) {
05028                 const cfg_obj_t *obj = cfg_listelt_value(element);
05029 
05030                 if (cfg_obj_isuint32(obj)) {
05031                         in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
05032 
05033                         if (positive)
05034                                 isc_portset_add(portset, port);
05035                         else
05036                                 isc_portset_remove(portset, port);
05037                 } else {
05038                         const cfg_obj_t *obj_loport, *obj_hiport;
05039                         in_port_t loport, hiport;
05040 
05041                         obj_loport = cfg_tuple_get(obj, "loport");
05042                         loport = (in_port_t)cfg_obj_asuint32(obj_loport);
05043                         obj_hiport = cfg_tuple_get(obj, "hiport");
05044                         hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
05045 
05046                         if (positive)
05047                                 isc_portset_addrange(portset, loport, hiport);
05048                         else {
05049                                 isc_portset_removerange(portset, loport,
05050                                                         hiport);
05051                         }
05052                 }
05053         }
05054 }
05055 
05056 static isc_result_t
05057 removed(dns_zone_t *zone, void *uap) {
05058         const char *type;
05059 
05060         if (dns_zone_getview(zone) != uap)
05061                 return (ISC_R_SUCCESS);
05062 
05063         switch (dns_zone_gettype(zone)) {
05064         case dns_zone_master:
05065                 type = "master";
05066                 break;
05067         case dns_zone_slave:
05068                 type = "slave";
05069                 break;
05070         case dns_zone_stub:
05071                 type = "stub";
05072                 break;
05073         case dns_zone_staticstub:
05074                 type = "static-stub";
05075                 break;
05076         case dns_zone_redirect:
05077                 type = "redirect";
05078                 break;
05079         default:
05080                 type = "other";
05081                 break;
05082         }
05083         dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type);
05084         return (ISC_R_SUCCESS);
05085 }
05086 
05087 static void
05088 cleanup_session_key(ns_server_t *server, isc_mem_t *mctx) {
05089         if (server->session_keyfile != NULL) {
05090                 isc_file_remove(server->session_keyfile);
05091                 isc_mem_free(mctx, server->session_keyfile);
05092                 server->session_keyfile = NULL;
05093         }
05094 
05095         if (server->session_keyname != NULL) {
05096                 if (dns_name_dynamic(server->session_keyname))
05097                         dns_name_free(server->session_keyname, mctx);
05098                 isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
05099                 server->session_keyname = NULL;
05100         }
05101 
05102         if (server->sessionkey != NULL)
05103                 dns_tsigkey_detach(&server->sessionkey);
05104 
05105         server->session_keyalg = DST_ALG_UNKNOWN;
05106         server->session_keybits = 0;
05107 }
05108 
05109 static isc_result_t
05110 generate_session_key(const char *filename, const char *keynamestr,
05111                      dns_name_t *keyname, const char *algstr,
05112                      dns_name_t *algname, unsigned int algtype,
05113                      isc_uint16_t bits, isc_mem_t *mctx,
05114                      dns_tsigkey_t **tsigkeyp)
05115 {
05116         isc_result_t result = ISC_R_SUCCESS;
05117         dst_key_t *key = NULL;
05118         isc_buffer_t key_txtbuffer;
05119         isc_buffer_t key_rawbuffer;
05120         char key_txtsecret[256];
05121         char key_rawsecret[64];
05122         isc_region_t key_rawregion;
05123         isc_stdtime_t now;
05124         dns_tsigkey_t *tsigkey = NULL;
05125         FILE *fp = NULL;
05126 
05127         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05128                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
05129                       "generating session key for dynamic DNS");
05130 
05131         /* generate key */
05132         result = dst_key_generate(keyname, algtype, bits, 1, 0,
05133                                   DNS_KEYPROTO_ANY, dns_rdataclass_in,
05134                                   mctx, &key);
05135         if (result != ISC_R_SUCCESS)
05136                 return (result);
05137 
05138         /*
05139          * Dump the key to the buffer for later use.  Should be done before
05140          * we transfer the ownership of key to tsigkey.
05141          */
05142         isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
05143         CHECK(dst_key_tobuffer(key, &key_rawbuffer));
05144 
05145         isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
05146         isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
05147         CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
05148 
05149         /* Store the key in tsigkey. */
05150         isc_stdtime_get(&now);
05151         CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key,
05152                                         ISC_FALSE, NULL, now, now, mctx, NULL,
05153                                         &tsigkey));
05154 
05155         /* Dump the key to the key file. */
05156         fp = ns_os_openfile(filename, S_IRUSR|S_IWUSR, ISC_TRUE);
05157         if (fp == NULL) {
05158                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05159                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
05160                               "could not create %s", filename);
05161                 result = ISC_R_NOPERM;
05162                 goto cleanup;
05163         }
05164 
05165         fprintf(fp, "key \"%s\" {\n"
05166                 "\talgorithm %s;\n"
05167                 "\tsecret \"%.*s\";\n};\n", keynamestr, algstr,
05168                 (int) isc_buffer_usedlength(&key_txtbuffer),
05169                 (char*) isc_buffer_base(&key_txtbuffer));
05170 
05171         CHECK(isc_stdio_flush(fp));
05172         CHECK(isc_stdio_close(fp));
05173 
05174         dst_key_free(&key);
05175 
05176         *tsigkeyp = tsigkey;
05177 
05178         return (ISC_R_SUCCESS);
05179 
05180   cleanup:
05181         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05182                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
05183                       "failed to generate session key "
05184                       "for dynamic DNS: %s", isc_result_totext(result));
05185         if (fp != NULL) {
05186                 (void)isc_stdio_close(fp);
05187                 (void)isc_file_remove(filename);
05188         }
05189         if (tsigkey != NULL)
05190                 dns_tsigkey_detach(&tsigkey);
05191         if (key != NULL)
05192                 dst_key_free(&key);
05193 
05194         return (result);
05195 }
05196 
05197 static isc_result_t
05198 configure_session_key(const cfg_obj_t **maps, ns_server_t *server,
05199                       isc_mem_t *mctx)
05200 {
05201         const char *keyfile, *keynamestr, *algstr;
05202         unsigned int algtype;
05203         dns_fixedname_t fname;
05204         dns_name_t *keyname, *algname;
05205         isc_buffer_t buffer;
05206         isc_uint16_t bits;
05207         const cfg_obj_t *obj;
05208         isc_boolean_t need_deleteold = ISC_FALSE;
05209         isc_boolean_t need_createnew = ISC_FALSE;
05210         isc_result_t result;
05211 
05212         obj = NULL;
05213         result = ns_config_get(maps, "session-keyfile", &obj);
05214         if (result == ISC_R_SUCCESS) {
05215                 if (cfg_obj_isvoid(obj))
05216                         keyfile = NULL; /* disable it */
05217                 else
05218                         keyfile = cfg_obj_asstring(obj);
05219         } else
05220                 keyfile = ns_g_defaultsessionkeyfile;
05221 
05222         obj = NULL;
05223         result = ns_config_get(maps, "session-keyname", &obj);
05224         INSIST(result == ISC_R_SUCCESS);
05225         keynamestr = cfg_obj_asstring(obj);
05226         dns_fixedname_init(&fname);
05227         isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
05228         isc_buffer_add(&buffer, strlen(keynamestr));
05229         keyname = dns_fixedname_name(&fname);
05230         result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
05231         if (result != ISC_R_SUCCESS)
05232                 return (result);
05233 
05234         obj = NULL;
05235         result = ns_config_get(maps, "session-keyalg", &obj);
05236         INSIST(result == ISC_R_SUCCESS);
05237         algstr = cfg_obj_asstring(obj);
05238         algname = NULL;
05239         result = ns_config_getkeyalgorithm2(algstr, &algname, &algtype, &bits);
05240         if (result != ISC_R_SUCCESS) {
05241                 const char *s = " (keeping current key)";
05242 
05243                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "session-keyalg: "
05244                             "unsupported or unknown algorithm '%s'%s",
05245                             algstr,
05246                             server->session_keyfile != NULL ? s : "");
05247                 return (result);
05248         }
05249 
05250         /* See if we need to (re)generate a new key. */
05251         if (keyfile == NULL) {
05252                 if (server->session_keyfile != NULL)
05253                         need_deleteold = ISC_TRUE;
05254         } else if (server->session_keyfile == NULL)
05255                 need_createnew = ISC_TRUE;
05256         else if (strcmp(keyfile, server->session_keyfile) != 0 ||
05257                  !dns_name_equal(server->session_keyname, keyname) ||
05258                  server->session_keyalg != algtype ||
05259                  server->session_keybits != bits) {
05260                 need_deleteold = ISC_TRUE;
05261                 need_createnew = ISC_TRUE;
05262         }
05263 
05264         if (need_deleteold) {
05265                 INSIST(server->session_keyfile != NULL);
05266                 INSIST(server->session_keyname != NULL);
05267                 INSIST(server->sessionkey != NULL);
05268 
05269                 cleanup_session_key(server, mctx);
05270         }
05271 
05272         if (need_createnew) {
05273                 INSIST(server->sessionkey == NULL);
05274                 INSIST(server->session_keyfile == NULL);
05275                 INSIST(server->session_keyname == NULL);
05276                 INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
05277                 INSIST(server->session_keybits == 0);
05278 
05279                 server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
05280                 if (server->session_keyname == NULL)
05281                         goto cleanup;
05282                 dns_name_init(server->session_keyname, NULL);
05283                 CHECK(dns_name_dup(keyname, mctx, server->session_keyname));
05284 
05285                 server->session_keyfile = isc_mem_strdup(mctx, keyfile);
05286                 if (server->session_keyfile == NULL)
05287                         goto cleanup;
05288 
05289                 server->session_keyalg = algtype;
05290                 server->session_keybits = bits;
05291 
05292                 CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
05293                                            algname, algtype, bits, mctx,
05294                                            &server->sessionkey));
05295         }
05296 
05297         return (result);
05298 
05299   cleanup:
05300         cleanup_session_key(server, mctx);
05301         return (result);
05302 }
05303 
05304 static isc_result_t
05305 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
05306                cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx)
05307 {
05308         isc_result_t result = ISC_R_SUCCESS;
05309         isc_boolean_t allow = ISC_FALSE;
05310         ns_cfgctx_t *nzcfg = NULL;
05311         const cfg_obj_t *maps[4];
05312         const cfg_obj_t *options = NULL, *voptions = NULL;
05313         const cfg_obj_t *nz = NULL;
05314         int i = 0;
05315 
05316         REQUIRE (config != NULL);
05317 
05318         if (vconfig != NULL)
05319                 voptions = cfg_tuple_get(vconfig, "options");
05320         if (voptions != NULL)
05321                 maps[i++] = voptions;
05322         result = cfg_map_get(config, "options", &options);
05323         if (result == ISC_R_SUCCESS)
05324                 maps[i++] = options;
05325         maps[i++] = ns_g_defaults;
05326         maps[i] = NULL;
05327 
05328         result = ns_config_get(maps, "allow-new-zones", &nz);
05329         if (result == ISC_R_SUCCESS)
05330                 allow = cfg_obj_asboolean(nz);
05331 
05332         if (!allow) {
05333                 dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
05334                 return (ISC_R_SUCCESS);
05335         }
05336 
05337         nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
05338         if (nzcfg == NULL) {
05339                 dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
05340                 return (ISC_R_NOMEMORY);
05341         }
05342 
05343         memset(nzcfg, 0, sizeof(*nzcfg));
05344 
05345         dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy);
05346 
05347         cfg_obj_attach(config, &nzcfg->config);
05348         if (vconfig != NULL)
05349                 cfg_obj_attach(vconfig, &nzcfg->vconfig);
05350 
05351         /*
05352          * We attach the parser that was used for config as well
05353          * as the one that will be used for added zones, to avoid
05354          * a shutdown race later.
05355          */
05356         cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
05357         cfg_parser_attach(ns_g_addparser, &nzcfg->add_parser);
05358         isc_mem_attach(view->mctx, &nzcfg->mctx);
05359         cfg_aclconfctx_attach(actx, &nzcfg->actx);
05360 
05361         /*
05362          * This may be called in multiple views, so we reset
05363          * the parser each time.
05364          */
05365         cfg_parser_reset(ns_g_addparser);
05366         result = cfg_parse_file(ns_g_addparser, view->new_zone_file,
05367                                 &cfg_type_newzones, &nzcfg->nzconfig);
05368 
05369         return (ISC_R_SUCCESS);
05370 }
05371 
05372 static int
05373 count_zones(const cfg_obj_t *conf) {
05374         const cfg_obj_t *zonelist = NULL;
05375         const cfg_listelt_t *element;
05376         int n = 0;
05377 
05378         REQUIRE(conf != NULL);
05379 
05380         cfg_map_get(conf, "zone", &zonelist);
05381         for (element = cfg_list_first(zonelist);
05382              element != NULL;
05383              element = cfg_list_next(element))
05384                 n++;
05385 
05386         return (n);
05387 }
05388 
05389 static isc_result_t
05390 check_lockfile(ns_server_t *server, const cfg_obj_t *config,
05391                isc_boolean_t first_time)
05392 {
05393         isc_result_t result;
05394         const char *filename = NULL;
05395         const cfg_obj_t *maps[3];
05396         const cfg_obj_t *options;
05397         const cfg_obj_t *obj;
05398         int i;
05399 
05400         i = 0;
05401         options = NULL;
05402         result = cfg_map_get(config, "options", &options);
05403         if (result == ISC_R_SUCCESS)
05404                 maps[i++] = options;
05405         maps[i++] = ns_g_defaults;
05406         maps[i] = NULL;
05407 
05408         obj = NULL;
05409         (void) ns_config_get(maps, "lock-file", &obj);
05410 
05411         if (!first_time) {
05412                 if (obj != NULL && !cfg_obj_isstring(obj) &&
05413                     server->lockfile != NULL &&
05414                     strcmp(cfg_obj_asstring(obj), server->lockfile) != 0)
05415                         isc_log_write(ns_g_lctx,
05416                                       NS_LOGCATEGORY_GENERAL,
05417                                       NS_LOGMODULE_SERVER,
05418                                       ISC_LOG_WARNING,
05419                                       "changing 'lock-file' "
05420                                       "has no effect until the "
05421                                       "server is restarted");
05422 
05423                 return (ISC_R_SUCCESS);
05424         }
05425 
05426         if (obj != NULL) {
05427                 if (cfg_obj_isvoid(obj)) {
05428                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05429                                       NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
05430                                       "skipping lock-file check ");
05431                         return (ISC_R_SUCCESS);
05432                 } else if (ns_g_forcelock) {
05433                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05434                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
05435                                       "'lock-file' has no effect "
05436                                       "because the server was run with -X");
05437                         server->lockfile = isc_mem_strdup(server->mctx,
05438                                                           ns_g_defaultlockfile);
05439                 } else {
05440                         filename = cfg_obj_asstring(obj);
05441                         server->lockfile = isc_mem_strdup(server->mctx,
05442                                                           filename);
05443                 }
05444 
05445                 if (server->lockfile == NULL)
05446                         return (ISC_R_NOMEMORY);
05447         }
05448 
05449         if (ns_g_forcelock && ns_g_defaultlockfile != NULL) {
05450                 INSIST(server->lockfile == NULL);
05451                 server->lockfile = isc_mem_strdup(server->mctx,
05452                                                   ns_g_defaultlockfile);
05453         }
05454 
05455         if (server->lockfile == NULL)
05456                 return (ISC_R_SUCCESS);
05457 
05458         if (ns_os_issingleton(server->lockfile))
05459                 return (ISC_R_SUCCESS);
05460 
05461         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05462                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
05463                       "could not lock %s; another named "
05464                       "process may be running", server->lockfile);
05465         return (ISC_R_FAILURE);
05466 }
05467 
05468 static isc_result_t
05469 load_configuration(const char *filename, ns_server_t *server,
05470                    isc_boolean_t first_time)
05471 {
05472         cfg_obj_t *config = NULL, *bindkeys = NULL;
05473         cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
05474         const cfg_listelt_t *element;
05475         const cfg_obj_t *builtin_views;
05476         const cfg_obj_t *maps[3];
05477         const cfg_obj_t *obj;
05478         const cfg_obj_t *options;
05479         const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
05480         const cfg_obj_t *views;
05481         dns_view_t *view = NULL;
05482         dns_view_t *view_next;
05483         dns_viewlist_t tmpviewlist;
05484         dns_viewlist_t viewlist, builtin_viewlist;
05485         in_port_t listen_port, udpport_low, udpport_high;
05486         int i;
05487         int num_zones = 0;
05488         isc_boolean_t exclusive = ISC_FALSE;
05489         isc_interval_t interval;
05490         isc_logconfig_t *logc = NULL;
05491         isc_portset_t *v4portset = NULL;
05492         isc_portset_t *v6portset = NULL;
05493         isc_resourcevalue_t nfiles;
05494         isc_result_t result, tresult;
05495         isc_uint32_t heartbeat_interval;
05496         isc_uint32_t interface_interval;
05497         isc_uint32_t reserved;
05498         isc_uint32_t udpsize;
05499         ns_cache_t *nsc;
05500         ns_cachelist_t cachelist, tmpcachelist;
05501         ns_cfgctx_t *nzctx;
05502         unsigned int maxsocks;
05503 
05504         ISC_LIST_INIT(viewlist);
05505         ISC_LIST_INIT(builtin_viewlist);
05506         ISC_LIST_INIT(cachelist);
05507 
05508         /* Create the ACL configuration context */
05509         if (ns_g_aclconfctx != NULL)
05510                 cfg_aclconfctx_detach(&ns_g_aclconfctx);
05511         CHECK(cfg_aclconfctx_create(ns_g_mctx, &ns_g_aclconfctx));
05512 
05513         /*
05514          * Parse the global default pseudo-config file.
05515          */
05516         if (first_time) {
05517                 CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
05518                 RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
05519                                           &ns_g_defaults) == ISC_R_SUCCESS);
05520         }
05521 
05522         /*
05523          * Parse the configuration file using the new config code.
05524          */
05525         result = ISC_R_FAILURE;
05526         config = NULL;
05527 
05528         /*
05529          * Unless this is lwresd with the -C option, parse the config file.
05530          */
05531         if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
05532                 isc_log_write(ns_g_lctx,
05533                               NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
05534                               ISC_LOG_INFO, "loading configuration from '%s'",
05535                               filename);
05536                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
05537                 cfg_parser_setcallback(conf_parser, directory_callback, NULL);
05538                 result = cfg_parse_file(conf_parser, filename,
05539                                         &cfg_type_namedconf, &config);
05540         }
05541 
05542         /*
05543          * If this is lwresd with the -C option, or lwresd with no -C or -c
05544          * option where the above parsing failed, parse resolv.conf.
05545          */
05546         if (ns_g_lwresdonly &&
05547             (lwresd_g_useresolvconf ||
05548              (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
05549         {
05550                 isc_log_write(ns_g_lctx,
05551                               NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
05552                               ISC_LOG_INFO, "loading configuration from '%s'",
05553                               lwresd_g_resolvconffile);
05554                 if (conf_parser != NULL)
05555                         cfg_parser_destroy(&conf_parser);
05556                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
05557                 result = ns_lwresd_parseeresolvconf(ns_g_mctx, conf_parser,
05558                                                     &config);
05559         }
05560         CHECK(result);
05561 
05562         /*
05563          * Check the validity of the configuration.
05564          */
05565         CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx));
05566 
05567         /*
05568          * Fill in the maps array, used for resolving defaults.
05569          */
05570         i = 0;
05571         options = NULL;
05572         result = cfg_map_get(config, "options", &options);
05573         if (result == ISC_R_SUCCESS)
05574                 maps[i++] = options;
05575         maps[i++] = ns_g_defaults;
05576         maps[i] = NULL;
05577 
05578         /*
05579          * If bind.keys exists, load it.  If "dnssec-validation auto"
05580          * is turned on, the root key found there will be used as a
05581          * default trust anchor, and if "dnssec-lookaside auto" is
05582          * turned on, then the DLV key found there will too.
05583          */
05584         obj = NULL;
05585         result = ns_config_get(maps, "bindkeys-file", &obj);
05586         INSIST(result == ISC_R_SUCCESS);
05587         CHECKM(setstring(server, &server->bindkeysfile,
05588                cfg_obj_asstring(obj)), "strdup");
05589 
05590         if (access(server->bindkeysfile, R_OK) == 0) {
05591                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05592                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
05593                               "reading built-in trusted "
05594                               "keys from file '%s'", server->bindkeysfile);
05595 
05596                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx,
05597                                         &bindkeys_parser));
05598 
05599                 result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
05600                                         &cfg_type_bindkeys, &bindkeys);
05601                 CHECK(result);
05602         }
05603 
05604         /* Ensure exclusive access to configuration data. */
05605         if (!exclusive) {
05606                 result = isc_task_beginexclusive(server->task);
05607                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
05608                 exclusive = ISC_TRUE;
05609         }
05610 
05611         /*
05612          * Set process limits, which (usually) needs to be done as root.
05613          */
05614         set_limits(maps);
05615 
05616         /*
05617          * Check the process lockfile.
05618          */
05619         CHECK(check_lockfile(server, config, first_time));
05620 
05621         /*
05622          * Check if max number of open sockets that the system allows is
05623          * sufficiently large.  Failing this condition is not necessarily fatal,
05624          * but may cause subsequent runtime failures for a busy recursive
05625          * server.
05626          */
05627         result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks);
05628         if (result != ISC_R_SUCCESS)
05629                 maxsocks = 0;
05630         result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
05631         if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
05632                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05633                               NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
05634                               "max open files (%" ISC_PRINT_QUADFORMAT "u)"
05635                               " is smaller than max sockets (%u)",
05636                               nfiles, maxsocks);
05637         }
05638 
05639         /*
05640          * Set the number of socket reserved for TCP, stdio etc.
05641          */
05642         obj = NULL;
05643         result = ns_config_get(maps, "reserved-sockets", &obj);
05644         INSIST(result == ISC_R_SUCCESS);
05645         reserved = cfg_obj_asuint32(obj);
05646         if (maxsocks != 0) {
05647                 if (maxsocks < 128U)                    /* Prevent underflow. */
05648                         reserved = 0;
05649                 else if (reserved > maxsocks - 128U)    /* Minimum UDP space. */
05650                         reserved = maxsocks - 128;
05651         }
05652         /* Minimum TCP/stdio space. */
05653         if (reserved < 128U)
05654                 reserved = 128;
05655         if (reserved + 128U > maxsocks && maxsocks != 0) {
05656                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05657                               NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
05658                               "less than 128 UDP sockets available after "
05659                               "applying 'reserved-sockets' and 'maxsockets'");
05660         }
05661         isc__socketmgr_setreserved(ns_g_socketmgr, reserved);
05662 
05663 #ifdef HAVE_GEOIP
05664         /*
05665          * Initialize GeoIP databases from the configured location.
05666          * This should happen before configuring any ACLs, so that we
05667          * know what databases are available and can reject any GeoIP
05668          * ACLs that can't work.
05669          */
05670         obj = NULL;
05671         result = ns_config_get(maps, "geoip-directory", &obj);
05672         if (result == ISC_R_SUCCESS && cfg_obj_isstring(obj)) {
05673                 char *dir;
05674                 DE_CONST(cfg_obj_asstring(obj), dir);
05675                 ns_geoip_load(dir);
05676         } else
05677                 ns_geoip_load(NULL);
05678         ns_g_aclconfctx->geoip = ns_g_geoip;
05679 
05680         obj = NULL;
05681         result = ns_config_get(maps, "geoip-use-ecs", &obj);
05682         INSIST(result == ISC_R_SUCCESS);
05683         ns_g_server->aclenv.geoip_use_ecs = cfg_obj_asboolean(obj);
05684 #endif /* HAVE_GEOIP */
05685 
05686         /*
05687          * Configure various server options.
05688          */
05689         configure_server_quota(maps, "transfers-out", &server->xfroutquota);
05690         configure_server_quota(maps, "tcp-clients", &server->tcpquota);
05691         configure_server_quota(maps, "recursive-clients",
05692                                &server->recursionquota);
05693         if (server->recursionquota.max > 1000)
05694                 isc_quota_soft(&server->recursionquota,
05695                                server->recursionquota.max - 100);
05696         else
05697                 isc_quota_soft(&server->recursionquota, 0);
05698 
05699         CHECK(configure_view_acl(NULL, config, "blackhole", NULL,
05700                                  ns_g_aclconfctx, ns_g_mctx,
05701                                  &server->blackholeacl));
05702         if (server->blackholeacl != NULL)
05703                 dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
05704                                              server->blackholeacl);
05705 
05706         CHECK(configure_view_acl(NULL, config, "keep-response-order", NULL,
05707                                  ns_g_aclconfctx, ns_g_mctx,
05708                                  &server->keepresporder));
05709 
05710         obj = NULL;
05711         result = ns_config_get(maps, "match-mapped-addresses", &obj);
05712         INSIST(result == ISC_R_SUCCESS);
05713         server->aclenv.match_mapped = cfg_obj_asboolean(obj);
05714 
05715         CHECKM(ns_statschannels_configure(ns_g_server, config, ns_g_aclconfctx),
05716                "configuring statistics server(s)");
05717 
05718         /*
05719          * Configure sets of UDP query source ports.
05720          */
05721         CHECKM(isc_portset_create(ns_g_mctx, &v4portset),
05722                "creating UDP port set");
05723         CHECKM(isc_portset_create(ns_g_mctx, &v6portset),
05724                "creating UDP port set");
05725 
05726         usev4ports = NULL;
05727         usev6ports = NULL;
05728         avoidv4ports = NULL;
05729         avoidv6ports = NULL;
05730 
05731         (void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports);
05732         if (usev4ports != NULL)
05733                 portset_fromconf(v4portset, usev4ports, ISC_TRUE);
05734         else {
05735                 CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
05736                                                &udpport_high),
05737                        "get the default UDP/IPv4 port range");
05738                 if (udpport_low == udpport_high)
05739                         isc_portset_add(v4portset, udpport_low);
05740                 else {
05741                         isc_portset_addrange(v4portset, udpport_low,
05742                                              udpport_high);
05743                 }
05744                 if (!ns_g_disable4)
05745                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05746                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
05747                                       "using default UDP/IPv4 port range: "
05748                                       "[%d, %d]", udpport_low, udpport_high);
05749         }
05750         (void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
05751         if (avoidv4ports != NULL)
05752                 portset_fromconf(v4portset, avoidv4ports, ISC_FALSE);
05753 
05754         (void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports);
05755         if (usev6ports != NULL)
05756                 portset_fromconf(v6portset, usev6ports, ISC_TRUE);
05757         else {
05758                 CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
05759                                                &udpport_high),
05760                        "get the default UDP/IPv6 port range");
05761                 if (udpport_low == udpport_high)
05762                         isc_portset_add(v6portset, udpport_low);
05763                 else {
05764                         isc_portset_addrange(v6portset, udpport_low,
05765                                              udpport_high);
05766                 }
05767                 if (!ns_g_disable6)
05768                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05769                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
05770                                       "using default UDP/IPv6 port range: "
05771                                       "[%d, %d]", udpport_low, udpport_high);
05772         }
05773         (void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
05774         if (avoidv6ports != NULL)
05775                 portset_fromconf(v6portset, avoidv6ports, ISC_FALSE);
05776 
05777         dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset);
05778 
05779         /*
05780          * Set the EDNS UDP size when we don't match a view.
05781          */
05782         obj = NULL;
05783         result = ns_config_get(maps, "edns-udp-size", &obj);
05784         INSIST(result == ISC_R_SUCCESS);
05785         udpsize = cfg_obj_asuint32(obj);
05786         if (udpsize < 512)
05787                 udpsize = 512;
05788         if (udpsize > 4096)
05789                 udpsize = 4096;
05790         ns_g_udpsize = (isc_uint16_t)udpsize;
05791 
05792         /*
05793          * Configure the zone manager.
05794          */
05795         obj = NULL;
05796         result = ns_config_get(maps, "transfers-in", &obj);
05797         INSIST(result == ISC_R_SUCCESS);
05798         dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
05799 
05800         obj = NULL;
05801         result = ns_config_get(maps, "transfers-per-ns", &obj);
05802         INSIST(result == ISC_R_SUCCESS);
05803         dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
05804 
05805         obj = NULL;
05806         result = ns_config_get(maps, "notify-rate", &obj);
05807         INSIST(result == ISC_R_SUCCESS);
05808         dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
05809 
05810         obj = NULL;
05811         result = ns_config_get(maps, "startup-notify-rate", &obj);
05812         INSIST(result == ISC_R_SUCCESS);
05813         dns_zonemgr_setstartupnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
05814 
05815         obj = NULL;
05816         result = ns_config_get(maps, "serial-query-rate", &obj);
05817         INSIST(result == ISC_R_SUCCESS);
05818         dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
05819 
05820         /*
05821          * Determine which port to use for listening for incoming connections.
05822          */
05823         if (ns_g_port != 0)
05824                 listen_port = ns_g_port;
05825         else
05826                 CHECKM(ns_config_getport(config, &listen_port), "port");
05827 
05828         /*
05829          * Determing the default DSCP code point.
05830          */
05831         CHECKM(ns_config_getdscp(config, &ns_g_dscp), "dscp");
05832 
05833         /*
05834          * Find the listen queue depth.
05835          */
05836         obj = NULL;
05837         result = ns_config_get(maps, "tcp-listen-queue", &obj);
05838         INSIST(result == ISC_R_SUCCESS);
05839         ns_g_listen = cfg_obj_asuint32(obj);
05840         if ((ns_g_listen > 0) && (ns_g_listen < 10))
05841                 ns_g_listen = 10;
05842 
05843         /*
05844          * Configure the interface manager according to the "listen-on"
05845          * statement.
05846          */
05847         {
05848                 const cfg_obj_t *clistenon = NULL;
05849                 ns_listenlist_t *listenon = NULL;
05850 
05851                 clistenon = NULL;
05852                 /*
05853                  * Even though listen-on is present in the default
05854                  * configuration, we can't use it here, since it isn't
05855                  * used if we're in lwresd mode.  This way is easier.
05856                  */
05857                 if (options != NULL)
05858                         (void)cfg_map_get(options, "listen-on", &clistenon);
05859                 if (clistenon != NULL) {
05860                         /* check return code? */
05861                         (void)ns_listenlist_fromconfig(clistenon, config,
05862                                                        ns_g_aclconfctx,
05863                                                        ns_g_mctx, AF_INET,
05864                                                        &listenon);
05865                 } else if (!ns_g_lwresdonly) {
05866                         /*
05867                          * Not specified, use default.
05868                          */
05869                         CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
05870                                                     -1, ISC_TRUE, &listenon));
05871                 }
05872                 if (listenon != NULL) {
05873                         ns_interfacemgr_setlistenon4(server->interfacemgr,
05874                                                      listenon);
05875                         ns_listenlist_detach(&listenon);
05876                 }
05877         }
05878         /*
05879          * Ditto for IPv6.
05880          */
05881         {
05882                 const cfg_obj_t *clistenon = NULL;
05883                 ns_listenlist_t *listenon = NULL;
05884 
05885                 if (options != NULL)
05886                         (void)cfg_map_get(options, "listen-on-v6", &clistenon);
05887                 if (clistenon != NULL) {
05888                         /* check return code? */
05889                         (void)ns_listenlist_fromconfig(clistenon, config,
05890                                                        ns_g_aclconfctx,
05891                                                        ns_g_mctx, AF_INET6,
05892                                                        &listenon);
05893                 } else if (!ns_g_lwresdonly) {
05894                         /*
05895                          * Not specified, use default.
05896                          */
05897                         CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
05898                                                     -1, ISC_TRUE, &listenon));
05899                 }
05900                 if (listenon != NULL) {
05901                         ns_interfacemgr_setlistenon6(server->interfacemgr,
05902                                                      listenon);
05903                         ns_listenlist_detach(&listenon);
05904                 }
05905         }
05906 
05907         /*
05908          * Rescan the interface list to pick up changes in the
05909          * listen-on option.  It's important that we do this before we try
05910          * to configure the query source, since the dispatcher we use might
05911          * be shared with an interface.
05912          */
05913         result = scan_interfaces(server, ISC_TRUE);
05914 
05915         /*
05916          * Check that named is able to TCP listen on at least one
05917          * interface. Otherwise, another named process could be running
05918          * and we should fail.
05919          */
05920         if (first_time && (result == ISC_R_ADDRINUSE)) {
05921                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05922                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
05923                               "unable to listen on any configured interfaces");
05924                 result = ISC_R_FAILURE;
05925                 goto cleanup;
05926         }
05927 
05928         /*
05929          * Arrange for further interface scanning to occur periodically
05930          * as specified by the "interface-interval" option.
05931          */
05932         obj = NULL;
05933         result = ns_config_get(maps, "interface-interval", &obj);
05934         INSIST(result == ISC_R_SUCCESS);
05935         interface_interval = cfg_obj_asuint32(obj) * 60;
05936         if (interface_interval == 0) {
05937                 CHECK(isc_timer_reset(server->interface_timer,
05938                                       isc_timertype_inactive,
05939                                       NULL, NULL, ISC_TRUE));
05940         } else if (server->interface_interval != interface_interval) {
05941                 isc_interval_set(&interval, interface_interval, 0);
05942                 CHECK(isc_timer_reset(server->interface_timer,
05943                                       isc_timertype_ticker,
05944                                       NULL, &interval, ISC_FALSE));
05945         }
05946         server->interface_interval = interface_interval;
05947 
05948         /*
05949          * Enable automatic interface scans.
05950          */
05951         obj = NULL;
05952         result = ns_config_get(maps, "automatic-interface-scan", &obj);
05953         INSIST(result == ISC_R_SUCCESS);
05954         server->interface_auto = cfg_obj_asboolean(obj);
05955 
05956         /*
05957          * Configure the dialup heartbeat timer.
05958          */
05959         obj = NULL;
05960         result = ns_config_get(maps, "heartbeat-interval", &obj);
05961         INSIST(result == ISC_R_SUCCESS);
05962         heartbeat_interval = cfg_obj_asuint32(obj) * 60;
05963         if (heartbeat_interval == 0) {
05964                 CHECK(isc_timer_reset(server->heartbeat_timer,
05965                                       isc_timertype_inactive,
05966                                       NULL, NULL, ISC_TRUE));
05967         } else if (server->heartbeat_interval != heartbeat_interval) {
05968                 isc_interval_set(&interval, heartbeat_interval, 0);
05969                 CHECK(isc_timer_reset(server->heartbeat_timer,
05970                                       isc_timertype_ticker,
05971                                       NULL, &interval, ISC_FALSE));
05972         }
05973         server->heartbeat_interval = heartbeat_interval;
05974 
05975         isc_interval_set(&interval, 1200, 0);
05976         CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
05977                               &interval, ISC_FALSE));
05978 
05979         /*
05980          * Write the PID file.
05981          */
05982         obj = NULL;
05983         if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
05984                 if (cfg_obj_isvoid(obj))
05985                         ns_os_writepidfile(NULL, first_time);
05986                 else
05987                         ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
05988         else if (ns_g_lwresdonly)
05989                 ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
05990         else
05991                 ns_os_writepidfile(ns_g_defaultpidfile, first_time);
05992 
05993         /*
05994          * Configure the server-wide session key.  This must be done before
05995          * configure views because zone configuration may need to know
05996          * session-keyname.
05997          *
05998          * Failure of session key generation isn't fatal at this time; if it
05999          * turns out that a session key is really needed but doesn't exist,
06000          * we'll treat it as a fatal error then.
06001          */
06002         (void)configure_session_key(maps, server, ns_g_mctx);
06003 
06004         views = NULL;
06005         (void)cfg_map_get(config, "view", &views);
06006 
06007         /*
06008          * Create the views and count all the configured zones in
06009          * order to correctly size the zone manager's task table.
06010          * (We only count zones for configured views; the built-in
06011          * "bind" view can be ignored as it only adds a negligible
06012          * number of zones.)
06013          *
06014          * If we're allowing new zones, we need to be able to find the
06015          * new zone file and count those as well.  So we setup the new
06016          * zone configuration context, but otherwise view configuration
06017          * waits until after the zone manager's task list has been sized.
06018          */
06019         for (element = cfg_list_first(views);
06020              element != NULL;
06021              element = cfg_list_next(element))
06022         {
06023                 cfg_obj_t *vconfig = cfg_listelt_value(element);
06024                 const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
06025                 view = NULL;
06026 
06027                 CHECK(create_view(vconfig, &viewlist, &view));
06028                 INSIST(view != NULL);
06029 
06030                 num_zones += count_zones(voptions);
06031 
06032                 CHECK(setup_newzones(view, config, vconfig, conf_parser,
06033                                      ns_g_aclconfctx));
06034                 nzctx = view->new_zone_config;
06035                 if (nzctx != NULL && nzctx->nzconfig != NULL)
06036                         num_zones += count_zones(nzctx->nzconfig);
06037 
06038                 dns_view_detach(&view);
06039         }
06040 
06041         /*
06042          * If there were no explicit views then we do the default
06043          * view here.
06044          */
06045         if (views == NULL) {
06046                 CHECK(create_view(NULL, &viewlist, &view));
06047                 INSIST(view != NULL);
06048 
06049                 num_zones = count_zones(config);
06050 
06051                 CHECK(setup_newzones(view, config, NULL, conf_parser,
06052                                      ns_g_aclconfctx));
06053 
06054                 nzctx = view->new_zone_config;
06055                 if (nzctx != NULL && nzctx->nzconfig != NULL)
06056                         num_zones += count_zones(nzctx->nzconfig);
06057 
06058                 dns_view_detach(&view);
06059         }
06060 
06061         /*
06062          * Zones have been counted; set the zone manager task pool size.
06063          */
06064         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
06065                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
06066                       "sizing zone task pool based on %d zones", num_zones);
06067         CHECK(dns_zonemgr_setsize(ns_g_server->zonemgr, num_zones));
06068 
06069         /*
06070          * Configure and freeze all explicit views.  Explicit
06071          * views that have zones were already created at parsing
06072          * time, but views with no zones must be created here.
06073          */
06074         for (element = cfg_list_first(views);
06075              element != NULL;
06076              element = cfg_list_next(element))
06077         {
06078                 cfg_obj_t *vconfig = cfg_listelt_value(element);
06079 
06080                 view = NULL;
06081                 CHECK(find_view(vconfig, &viewlist, &view));
06082                 CHECK(configure_view(view, &viewlist, config, vconfig,
06083                                      &cachelist, bindkeys, ns_g_mctx,
06084                                      ns_g_aclconfctx, ISC_TRUE));
06085                 dns_view_freeze(view);
06086                 dns_view_detach(&view);
06087         }
06088 
06089         /*
06090          * Make sure we have a default view if and only if there
06091          * were no explicit views.
06092          */
06093         if (views == NULL) {
06094                 view = NULL;
06095                 CHECK(find_view(NULL, &viewlist, &view));
06096                 CHECK(configure_view(view, &viewlist, config, NULL,
06097                                      &cachelist, bindkeys,
06098                                      ns_g_mctx, ns_g_aclconfctx, ISC_TRUE));
06099                 dns_view_freeze(view);
06100                 dns_view_detach(&view);
06101         }
06102 
06103         /*
06104          * Create (or recreate) the built-in views.
06105          */
06106         builtin_views = NULL;
06107         RUNTIME_CHECK(cfg_map_get(ns_g_config, "view",
06108                                   &builtin_views) == ISC_R_SUCCESS);
06109         for (element = cfg_list_first(builtin_views);
06110              element != NULL;
06111              element = cfg_list_next(element))
06112         {
06113                 cfg_obj_t *vconfig = cfg_listelt_value(element);
06114 
06115                 CHECK(create_view(vconfig, &builtin_viewlist, &view));
06116                 CHECK(configure_view(view, &viewlist, config, vconfig,
06117                                      &cachelist, bindkeys,
06118                                      ns_g_mctx, ns_g_aclconfctx, ISC_FALSE));
06119                 dns_view_freeze(view);
06120                 dns_view_detach(&view);
06121                 view = NULL;
06122         }
06123 
06124         /* Now combine the two viewlists into one */
06125         ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
06126 
06127         /* Swap our new view list with the production one. */
06128         tmpviewlist = server->viewlist;
06129         server->viewlist = viewlist;
06130         viewlist = tmpviewlist;
06131 
06132         /* Make the view list available to each of the views */
06133         view = ISC_LIST_HEAD(server->viewlist);
06134         while (view != NULL) {
06135                 view->viewlist = &server->viewlist;
06136                 view = ISC_LIST_NEXT(view, link);
06137         }
06138 
06139         /* Swap our new cache list with the production one. */
06140         tmpcachelist = server->cachelist;
06141         server->cachelist = cachelist;
06142         cachelist = tmpcachelist;
06143 
06144         /* Load the TKEY information from the configuration. */
06145         if (options != NULL) {
06146                 dns_tkeyctx_t *t = NULL;
06147                 CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
06148                                              &t),
06149                        "configuring TKEY");
06150                 if (server->tkeyctx != NULL)
06151                         dns_tkeyctx_destroy(&server->tkeyctx);
06152                 server->tkeyctx = t;
06153         }
06154 
06155         /*
06156          * Bind the control port(s).
06157          */
06158         CHECKM(ns_controls_configure(ns_g_server->controls, config,
06159                                      ns_g_aclconfctx),
06160                "binding control channel(s)");
06161 
06162         /*
06163          * Bind the lwresd port(s).
06164          */
06165         CHECKM(ns_lwresd_configure(ns_g_mctx, config),
06166                "binding lightweight resolver ports");
06167 
06168         /*
06169          * Open the source of entropy.
06170          */
06171         if (first_time) {
06172                 obj = NULL;
06173                 result = ns_config_get(maps, "random-device", &obj);
06174                 if (result != ISC_R_SUCCESS) {
06175                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
06176                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
06177                                       "no source of entropy found");
06178                 } else {
06179                         const char *randomdev = cfg_obj_asstring(obj);
06180                         result = isc_entropy_createfilesource(ns_g_entropy,
06181                                                               randomdev);
06182                         if (result != ISC_R_SUCCESS)
06183                                 isc_log_write(ns_g_lctx,
06184                                               NS_LOGCATEGORY_GENERAL,
06185                                               NS_LOGMODULE_SERVER,
06186                                               ISC_LOG_INFO,
06187                                               "could not open entropy source "
06188                                               "%s: %s",
06189                                               randomdev,
06190                                               isc_result_totext(result));
06191 #ifdef PATH_RANDOMDEV
06192                         if (ns_g_fallbackentropy != NULL) {
06193                                 if (result != ISC_R_SUCCESS) {
06194                                         isc_log_write(ns_g_lctx,
06195                                                       NS_LOGCATEGORY_GENERAL,
06196                                                       NS_LOGMODULE_SERVER,
06197                                                       ISC_LOG_INFO,
06198                                                       "using pre-chroot entropy source "
06199                                                       "%s",
06200                                                       PATH_RANDOMDEV);
06201                                         isc_entropy_detach(&ns_g_entropy);
06202                                         isc_entropy_attach(ns_g_fallbackentropy,
06203                                                            &ns_g_entropy);
06204                                 }
06205                                 isc_entropy_detach(&ns_g_fallbackentropy);
06206                         }
06207 #endif
06208                 }
06209         }
06210 
06211         /*
06212          * Relinquish root privileges.
06213          */
06214         if (first_time)
06215                 ns_os_changeuser();
06216 
06217         /*
06218          * Check that the working directory is writable.
06219          */
06220         if (access(".", W_OK) != 0) {
06221                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
06222                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
06223                               "the working directory is not writable");
06224         }
06225 
06226         /*
06227          * Configure the logging system.
06228          *
06229          * Do this after changing UID to make sure that any log
06230          * files specified in named.conf get created by the
06231          * unprivileged user, not root.
06232          */
06233         if (ns_g_logstderr) {
06234                 const cfg_obj_t *logobj = NULL;
06235 
06236                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
06237                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
06238                               "not using config file logging "
06239                               "statement for logging due to "
06240                               "-g option");
06241 
06242                 (void)cfg_map_get(config, "logging", &logobj);
06243                 if (logobj != NULL) {
06244                         result = ns_log_configure(NULL, logobj);
06245                         if (result != ISC_R_SUCCESS) {
06246                                 isc_log_write(ns_g_lctx,
06247                                               NS_LOGCATEGORY_GENERAL,
06248                                               NS_LOGMODULE_SERVER,
06249                                               ISC_LOG_ERROR,
06250                                               "checking logging configuration "
06251                                               "failed: %s",
06252                                               isc_result_totext(result));
06253                                 goto cleanup;
06254                         }
06255                 }
06256         } else {
06257                 const cfg_obj_t *logobj = NULL;
06258 
06259                 CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
06260                        "creating new logging configuration");
06261 
06262                 logobj = NULL;
06263                 (void)cfg_map_get(config, "logging", &logobj);
06264                 if (logobj != NULL) {
06265                         CHECKM(ns_log_configure(logc, logobj),
06266                                "configuring logging");
06267                 } else {
06268                         CHECKM(ns_log_setdefaultchannels(logc),
06269                                "setting up default logging channels");
06270                         CHECKM(ns_log_setunmatchedcategory(logc),
06271                                "setting up default 'category unmatched'");
06272                         CHECKM(ns_log_setdefaultcategory(logc),
06273                                "setting up default 'category default'");
06274                 }
06275 
06276                 CHECKM(isc_logconfig_use(ns_g_lctx, logc),
06277                        "installing logging configuration");
06278                 logc = NULL;
06279 
06280                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
06281                               NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
06282                               "now using logging configuration from "
06283                               "config file");
06284         }
06285 
06286         /*
06287          * Set the default value of the query logging flag depending
06288          * whether a "queries" category has been defined.  This is
06289          * a disgusting hack, but we need to do this for BIND 8
06290          * compatibility.
06291          */
06292         if (first_time) {
06293                 const cfg_obj_t *logobj = NULL;
06294                 const cfg_obj_t *categories = NULL;
06295 
06296                 obj = NULL;
06297                 if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
06298                         server->log_queries = cfg_obj_asboolean(obj);
06299                 } else {
06300 
06301                         (void)cfg_map_get(config, "logging", &logobj);
06302                         if (logobj != NULL)
06303                                 (void)cfg_map_get(logobj, "category",
06304                                                   &categories);
06305                         if (categories != NULL) {
06306                                 for (element = cfg_list_first(categories);
06307                                      element != NULL;
06308                                      element = cfg_list_next(element))
06309                                 {
06310                                         const cfg_obj_t *catobj;
06311                                         const char *str;
06312 
06313                                         obj = cfg_listelt_value(element);
06314                                         catobj = cfg_tuple_get(obj, "name");
06315                                         str = cfg_obj_asstring(catobj);
06316                                         if (strcasecmp(str, "queries") == 0)
06317                                                 server->log_queries = ISC_TRUE;
06318                                 }
06319                         }
06320                 }
06321         }
06322 
06323 
06324         obj = NULL;
06325         if (options != NULL &&
06326             cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
06327                 ns_g_memstatistics = cfg_obj_asboolean(obj);
06328         else
06329                 ns_g_memstatistics =
06330                         ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
06331 
06332         obj = NULL;
06333         if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
06334                 ns_main_setmemstats(cfg_obj_asstring(obj));
06335         else if (ns_g_memstatistics)
06336                 ns_main_setmemstats("named.memstats");
06337         else
06338                 ns_main_setmemstats(NULL);
06339 
06340         obj = NULL;
06341         result = ns_config_get(maps, "statistics-file", &obj);
06342         INSIST(result == ISC_R_SUCCESS);
06343         CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
06344                "strdup");
06345 
06346         obj = NULL;
06347         result = ns_config_get(maps, "dump-file", &obj);
06348         INSIST(result == ISC_R_SUCCESS);
06349         CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
06350                "strdup");
06351 
06352         obj = NULL;
06353         result = ns_config_get(maps, "secroots-file", &obj);
06354         INSIST(result == ISC_R_SUCCESS);
06355         CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
06356                "strdup");
06357 
06358         obj = NULL;
06359         result = ns_config_get(maps, "recursing-file", &obj);
06360         INSIST(result == ISC_R_SUCCESS);
06361         CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
06362                "strdup");
06363 
06364         obj = NULL;
06365         result = ns_config_get(maps, "version", &obj);
06366         if (result == ISC_R_SUCCESS) {
06367                 CHECKM(setoptstring(server, &server->version, obj), "strdup");
06368                 server->version_set = ISC_TRUE;
06369         } else {
06370                 server->version_set = ISC_FALSE;
06371         }
06372 
06373         obj = NULL;
06374         result = ns_config_get(maps, "hostname", &obj);
06375         if (result == ISC_R_SUCCESS) {
06376                 CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
06377                 server->hostname_set = ISC_TRUE;
06378         } else {
06379                 server->hostname_set = ISC_FALSE;
06380         }
06381 
06382         obj = NULL;
06383         result = ns_config_get(maps, "server-id", &obj);
06384         server->server_usehostname = ISC_FALSE;
06385         if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
06386                 /* The parser translates "hostname" to ISC_TRUE */
06387                 server->server_usehostname = cfg_obj_asboolean(obj);
06388                 result = setstring(server, &server->server_id, NULL);
06389                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
06390         } else if (result == ISC_R_SUCCESS) {
06391                 /* Found a quoted string */
06392                 CHECKM(setoptstring(server, &server->server_id, obj), "strdup");
06393         } else {
06394                 result = setstring(server, &server->server_id, NULL);
06395                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
06396         }
06397 
06398         obj = NULL;
06399         result = ns_config_get(maps, "flush-zones-on-shutdown", &obj);
06400         if (result == ISC_R_SUCCESS) {
06401                 server->flushonshutdown = cfg_obj_asboolean(obj);
06402         } else {
06403                 server->flushonshutdown = ISC_FALSE;
06404         }
06405 
06406 #ifdef ISC_PLATFORM_USESIT
06407         obj = NULL;
06408         result = ns_config_get(maps, "sit-secret", &obj);
06409         if (result == ISC_R_SUCCESS) {
06410                 isc_buffer_t b;
06411 
06412                 memset(server->secret, 0, sizeof(server->secret));
06413                 isc_buffer_init(&b, server->secret, sizeof(server->secret));
06414                 result = isc_hex_decodestring(cfg_obj_asstring(obj), &b);
06415                 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
06416                         goto cleanup;
06417 #ifdef AES_SIT
06418                 if (isc_buffer_usedlength(&b) != ISC_AES128_KEYLENGTH)
06419                         CHECKM(ISC_R_RANGE,
06420                                "AES sit-secret must be on 128 bits");
06421 #endif
06422 #ifdef HMAC_SHA1_SIT
06423                 if (isc_buffer_usedlength(&b) != ISC_SHA1_DIGESTLENGTH)
06424                         CHECKM(ISC_R_RANGE,
06425                                "SHA1 sit-secret must be on 160 bits");
06426 #endif
06427 #ifdef HMAC_SHA256_SIT
06428                 if (isc_buffer_usedlength(&b) != ISC_SHA256_DIGESTLENGTH)
06429                         CHECKM(ISC_R_RANGE,
06430                                "SHA256 sit-secret must be on 256 bits");
06431 #endif
06432         } else {
06433                 result = isc_entropy_getdata(ns_g_entropy,
06434                                              server->secret,
06435                                              sizeof(server->secret),
06436                                              NULL,
06437                                              0);
06438                 if (result != ISC_R_SUCCESS)
06439                         goto cleanup;
06440         }
06441 #endif
06442 
06443         result = ISC_R_SUCCESS;
06444 
06445  cleanup:
06446         if (logc != NULL)
06447                 isc_logconfig_destroy(&logc);
06448 
06449         if (v4portset != NULL)
06450                 isc_portset_destroy(ns_g_mctx, &v4portset);
06451 
06452         if (v6portset != NULL)
06453                 isc_portset_destroy(ns_g_mctx, &v6portset);
06454 
06455         if (conf_parser != NULL) {
06456                 if (config != NULL)
06457                         cfg_obj_destroy(conf_parser, &config);
06458                 cfg_parser_destroy(&conf_parser);
06459         }
06460 
06461         if (bindkeys_parser != NULL) {
06462                 if (bindkeys != NULL)
06463                         cfg_obj_destroy(bindkeys_parser, &bindkeys);
06464                 cfg_parser_destroy(&bindkeys_parser);
06465         }
06466 
06467         if (view != NULL)
06468                 dns_view_detach(&view);
06469 
06470         ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
06471 
06472         /*
06473          * This cleans up either the old production view list
06474          * or our temporary list depending on whether they
06475          * were swapped above or not.
06476          */
06477         for (view = ISC_LIST_HEAD(viewlist);
06478              view != NULL;
06479              view = view_next) {
06480                 view_next = ISC_LIST_NEXT(view, link);
06481                 ISC_LIST_UNLINK(viewlist, view, link);
06482                 if (result == ISC_R_SUCCESS &&
06483                     strcmp(view->name, "_bind") != 0)
06484                         (void)dns_zt_apply(view->zonetable, ISC_FALSE,
06485                                            removed, view);
06486                 dns_view_detach(&view);
06487         }
06488 
06489         /* Same cleanup for cache list. */
06490         while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
06491                 ISC_LIST_UNLINK(cachelist, nsc, link);
06492                 dns_cache_detach(&nsc->cache);
06493                 isc_mem_put(server->mctx, nsc, sizeof(*nsc));
06494         }
06495 
06496         /*
06497          * Adjust the listening interfaces in accordance with the source
06498          * addresses specified in views and zones.
06499          */
06500         if (isc_net_probeipv6() == ISC_R_SUCCESS)
06501                 adjust_interfaces(server, ns_g_mctx);
06502 
06503         /*
06504          * Record the time of most recent configuration
06505          */
06506         tresult = isc_time_now(&ns_g_configtime);
06507         if (tresult != ISC_R_SUCCESS)
06508                 ns_main_earlyfatal("isc_time_now() failed: %s",
06509                                    isc_result_totext(result));
06510 
06511         /* Relinquish exclusive access to configuration data. */
06512         if (exclusive)
06513                 isc_task_endexclusive(server->task);
06514 
06515         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
06516                       ISC_LOG_DEBUG(1), "load_configuration: %s",
06517                       isc_result_totext(result));
06518 
06519         return (result);
06520 }
06521 
06522 static isc_result_t
06523 view_loaded(void *arg) {
06524         isc_result_t result;
06525         ns_zoneload_t *zl = (ns_zoneload_t *) arg;
06526         ns_server_t *server = zl->server;
06527         unsigned int refs;
06528 
06529 
06530         /*
06531          * Force zone maintenance.  Do this after loading
06532          * so that we know when we need to force AXFR of
06533          * slave zones whose master files are missing.
06534          *
06535          * We use the zoneload reference counter to let us
06536          * know when all views are finished.
06537          */
06538         isc_refcount_decrement(&zl->refs, &refs);
06539         if (refs != 0)
06540                 return (ISC_R_SUCCESS);
06541 
06542         isc_refcount_destroy(&zl->refs);
06543         isc_mem_put(server->mctx, zl, sizeof (*zl));
06544 
06545         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
06546                       ISC_LOG_NOTICE, "all zones loaded");
06547         CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
06548                    "forcing zone maintenance");
06549 
06550         ns_os_started();
06551         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
06552                       ISC_LOG_NOTICE, "running");
06553 
06554         return (ISC_R_SUCCESS);
06555 }
06556 
06557 static isc_result_t
06558 load_zones(ns_server_t *server, isc_boolean_t init) {
06559         isc_result_t result;
06560         dns_view_t *view;
06561         ns_zoneload_t *zl;
06562         unsigned int refs = 0;
06563 
06564         zl = isc_mem_get(server->mctx, sizeof (*zl));
06565         if (zl == NULL)
06566                 return (ISC_R_NOMEMORY);
06567         zl->server = server;
06568 
06569         result = isc_task_beginexclusive(server->task);
06570         RUNTIME_CHECK(result == ISC_R_SUCCESS);
06571 
06572         isc_refcount_init(&zl->refs, 1);
06573 
06574         /*
06575          * Schedule zones to be loaded from disk.
06576          */
06577         for (view = ISC_LIST_HEAD(server->viewlist);
06578              view != NULL;
06579              view = ISC_LIST_NEXT(view, link))
06580         {
06581                 if (view->managed_keys != NULL) {
06582                         result = dns_zone_load(view->managed_keys);
06583                         if (result != ISC_R_SUCCESS &&
06584                             result != DNS_R_UPTODATE &&
06585                             result != DNS_R_CONTINUE)
06586                                 goto cleanup;
06587                 }
06588                 if (view->redirect != NULL) {
06589                         result = dns_zone_load(view->redirect);
06590                         if (result != ISC_R_SUCCESS &&
06591                             result != DNS_R_UPTODATE &&
06592                             result != DNS_R_CONTINUE)
06593                                 goto cleanup;
06594                 }
06595 
06596                 /*
06597                  * 'dns_view_asyncload' calls view_loaded if there are no
06598                  * zones.
06599                  */
06600                 isc_refcount_increment(&zl->refs, NULL);
06601                 CHECK(dns_view_asyncload(view, view_loaded, zl));
06602         }
06603 
06604  cleanup:
06605         isc_refcount_decrement(&zl->refs, &refs);
06606         if (refs == 0) {
06607                 isc_refcount_destroy(&zl->refs);
06608                 isc_mem_put(server->mctx, zl, sizeof (*zl));
06609         } else if (init) {
06610                 /*
06611                  * Place the task manager into privileged mode.  This
06612                  * ensures that after we leave task-exclusive mode, no
06613                  * other tasks will be able to run except for the ones
06614                  * that are loading zones. (This should only be done during
06615                  * the initial server setup; it isn't necessary during
06616                  * a reload.)
06617                  */
06618                 isc_taskmgr_setmode(ns_g_taskmgr, isc_taskmgrmode_privileged);
06619         }
06620 
06621         isc_task_endexclusive(server->task);
06622         return (result);
06623 }
06624 
06625 static isc_result_t
06626 load_new_zones(ns_server_t *server, isc_boolean_t stop) {
06627         isc_result_t result;
06628         dns_view_t *view;
06629 
06630         result = isc_task_beginexclusive(server->task);
06631         RUNTIME_CHECK(result == ISC_R_SUCCESS);
06632 
06633         /*
06634          * Load zone data from disk.
06635          */
06636         for (view = ISC_LIST_HEAD(server->viewlist);
06637              view != NULL;
06638              view = ISC_LIST_NEXT(view, link))
06639         {
06640                 CHECK(dns_view_loadnew(view, stop));
06641 
06642                 /* Load managed-keys data */
06643                 if (view->managed_keys != NULL)
06644                         CHECK(dns_zone_loadnew(view->managed_keys));
06645                 if (view->redirect != NULL)
06646                         CHECK(dns_zone_loadnew(view->redirect));
06647         }
06648 
06649         /*
06650          * Resume zone XFRs.
06651          */
06652         dns_zonemgr_resumexfrs(server->zonemgr);
06653  cleanup:
06654         isc_task_endexclusive(server->task);
06655         return (result);
06656 }
06657 
06658 static void
06659 run_server(isc_task_t *task, isc_event_t *event) {
06660         isc_result_t result;
06661         ns_server_t *server = (ns_server_t *)event->ev_arg;
06662 
06663         INSIST(task == server->task);
06664 
06665         isc_event_free(&event);
06666 
06667         CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
06668                                           &ns_g_dispatchmgr),
06669                    "creating dispatch manager");
06670 
06671         dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats);
06672 
06673         CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
06674                                           ns_g_socketmgr, ns_g_dispatchmgr,
06675                                           server->task, &server->interfacemgr),
06676                    "creating interface manager");
06677 
06678         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
06679                                     NULL, NULL, server->task,
06680                                     interface_timer_tick,
06681                                     server, &server->interface_timer),
06682                    "creating interface timer");
06683 
06684         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
06685                                     NULL, NULL, server->task,
06686                                     heartbeat_timer_tick,
06687                                     server, &server->heartbeat_timer),
06688                    "creating heartbeat timer");
06689 
06690         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
06691                                     NULL, NULL, server->task, pps_timer_tick,
06692                                     server, &server->pps_timer),
06693                    "creating pps timer");
06694 
06695         CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
06696                    "creating default configuration parser");
06697 
06698         CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_addparser),
06699                    "creating additional configuration parser");
06700 
06701         if (ns_g_lwresdonly)
06702                 CHECKFATAL(load_configuration(lwresd_g_conffile, server,
06703                                               ISC_TRUE),
06704                            "loading configuration");
06705         else
06706                 CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
06707                            "loading configuration");
06708 
06709         isc_hash_init();
06710 
06711         CHECKFATAL(load_zones(server, ISC_TRUE), "loading zones");
06712 
06713         (void) ns_server_loadnta(server);
06714 }
06715 
06716 void
06717 ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
06718 
06719         REQUIRE(NS_SERVER_VALID(server));
06720 
06721         server->flushonshutdown = flush;
06722 }
06723 
06724 static void
06725 shutdown_server(isc_task_t *task, isc_event_t *event) {
06726         isc_result_t result;
06727         dns_view_t *view, *view_next;
06728         ns_server_t *server = (ns_server_t *)event->ev_arg;
06729         isc_boolean_t flush = server->flushonshutdown;
06730         ns_cache_t *nsc;
06731 
06732         UNUSED(task);
06733         INSIST(task == server->task);
06734 
06735         result = isc_task_beginexclusive(server->task);
06736         RUNTIME_CHECK(result == ISC_R_SUCCESS);
06737 
06738         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
06739                       ISC_LOG_INFO, "shutting down%s",
06740                       flush ? ": flushing changes" : "");
06741 
06742         ns_statschannels_shutdown(server);
06743         ns_controls_shutdown(server->controls);
06744         end_reserved_dispatches(server, ISC_TRUE);
06745         cleanup_session_key(server, server->mctx);
06746 
06747         if (ns_g_aclconfctx != NULL)
06748                 cfg_aclconfctx_detach(&ns_g_aclconfctx);
06749 
06750         cfg_obj_destroy(ns_g_parser, &ns_g_config);
06751         cfg_parser_destroy(&ns_g_parser);
06752         cfg_parser_destroy(&ns_g_addparser);
06753 
06754         (void) ns_server_saventa(server);
06755 
06756         for (view = ISC_LIST_HEAD(server->viewlist);
06757              view != NULL;
06758              view = view_next) {
06759                 view_next = ISC_LIST_NEXT(view, link);
06760                 ISC_LIST_UNLINK(server->viewlist, view, link);
06761                 if (flush)
06762                         dns_view_flushanddetach(&view);
06763                 else
06764                         dns_view_detach(&view);
06765         }
06766 
06767         while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
06768                 ISC_LIST_UNLINK(server-&g