bind server.c

整体功能分析

server.c 主要完成BIND 服务器的启动、关闭、reload、reconfig、refresh 等命令的处理,进行服务器、视图和区域配置的解析和处理。

函数调用关系

setup调用ns_server_create 函数创建默认服务器对象。

ns_server

定义在/bin/named/include/named/server.h
保存服务器配置。

struct
ns_server {
unsigned int magic;
isc_mem_t * mctx;
isc_task_t * task;
isc_quota_t xfroutquota; // transfers-out 配额
isc_quota_t tcpquota; // tcp-clients 配额
isc_quota_t recursionquota; // recursive-clients 配额
dns_acl_t *blackholeacl; // Blackhole ACL
char * statsfile; // 统计文件名
char * dumpfile; // Dump 文件名
char * recfile; // recursive 文件名
isc_boolean_t version_set; // 用户是否自定义版本
char * version; // 用户定义的版本
isc_boolean_t hostname_set; // 用户是否自定义主机名
char * hostname; // 用户定义的主机名
isc_boolean_t server_usehostname; // 将主机名作为server id
char * server_id; // 用户定义的server id
dns_aclenv_t aclenv; // 当前的ACL 环境
dns_loadmgr_t * loadmgr; // 负载管理器
dns_zonemgr_t * zonemgr; // 区域管理器
dns_viewlist_t viewlist; // 视图列表
ns_interfacemgr_t * interfacemgr; // 接口管理器
dns_db_t * in_roothints; // root hints
dns_tkeyctx_t * tkeyctx; // TKEY
isc_timer_t * interface_timer; // 计时器
isc_timer_t * heartbeat_timer;
isc_timer_t * pps_timer;
isc_uint32_t interface_interval; // 重新扫描网络接口间隔
isc_uint32_t heartbeat_interval;
isc_mutex_t reload_event_lock; // reload 事件锁
isc_event_t * reload_event; // reload 事件
isc_boolean_t flushonshutdown; // flush zones on
shutdown
isc_boolean_t log_queries; // 兼容BIND 8
dns_stats_t * nsstats; // 服务器统计
dns_stats_t * rcvquerystats; // 接收的查询请求统计
dns_stats_t * opcodestats; // 接收的消息统计
dns_stats_t * zonestats; // 区域管理器统计
dns_stats_t * resolverstats; // 解析器统计
ns_controls_t * controls; // 控制通道
unsigned int dispatchgen;
ns_dispatchlist_t dispatches; // 调度器
dns_acache_t *acache; // Additional section caching
ns_statschannellist_t statschannels; // 统计通道
};

主要代码

void
ns_server_create(isc_mem_t *mctx, ns_server_t **serverp)
{
    isc_result_t result;

    /*分配server内存*/
    ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
    ...

    /* Initialize configuration data with default values. */

    ...
    result = isc_quota_init(&server->recursionquota, 100);
    RUNTIME_CHECK(result == ISC_R_SUCCESS);

    result = dns_aclenv_init(mctx, &server->aclenv);
    RUNTIME_CHECK(result == ISC_R_SUCCESS);

    /* Initialize server data structures. */
    server->zonemgr = NULL;
    server->interfacemgr = NULL;
    ISC_LIST_INIT(server->viewlist);
    server->in_roothints = NULL;
    server->blackholeacl = NULL;

    CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
                     &server->in_roothints),
           "setting up root hints");

    CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
           "initializing reload event lock");
    server->reload_event =
        isc_event_allocate(ns_g_mctx, server,
                   NS_EVENT_RELOAD,
                   ns_server_reload,
                   server,
                   sizeof(isc_event_t));
    CHECKFATAL(server->reload_event == NULL ?
           ISC_R_NOMEMORY : ISC_R_SUCCESS,
           "allocating reload event");

    CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY),
           "initializing DST");

    server->tkeyctx = NULL;
    CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
                      &server->tkeyctx),
           "creating TKEY context");

    /*
     * Setup the server task, which is responsible for coordinating
     * startup and shutdown of the server.
     */
    CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
           "creating server task");
    isc_task_setname(server->task, "server", server);
    CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
           "isc_task_onshutdown");
    CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
           "isc_app_onrun");

    server->interface_timer = NULL;
    server->heartbeat_timer = NULL;
    server->pps_timer = NULL;

    server->interface_interval = 0;
    server->heartbeat_interval = 0;

    CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
                      ns_g_socketmgr, &server->zonemgr),
           "dns_zonemgr_create");

    server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
    CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
           "isc_mem_strdup");
    server->nsstats = NULL;
    server->rcvquerystats = NULL;
    server->opcodestats = NULL;
    server->zonestats = NULL;
    server->resolverstats = NULL;

    server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
    CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
           "isc_mem_strdup");

    server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
    CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
           "isc_mem_strdup");

    server->hostname_set = ISC_FALSE;
    server->hostname = NULL;
    server->version_set = ISC_FALSE;
    server->version = NULL;
    server->server_usehostname = ISC_FALSE;
    server->server_id = NULL;

    CHECKFATAL(dns_generalstats_create(ns_g_mctx, &server->nsstats,
                       dns_nsstatscounter_max),
           "dns_stats_create (server)");

    CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx,
                         &server->rcvquerystats),
           "dns_stats_create (rcvquery)");

    CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats),
           "dns_stats_create (opcode)");

    CHECKFATAL(dns_generalstats_create(ns_g_mctx, &server->zonestats,
                       dns_zonestatscounter_max),
           "dns_stats_create (zone)");

    CHECKFATAL(dns_generalstats_create(ns_g_mctx, &server->resolverstats,
                       dns_resstatscounter_max),
           "dns_stats_create (resolver)");

    server->flushonshutdown = ISC_FALSE;
    server->log_queries = ISC_FALSE;

    server->controls = NULL;
    CHECKFATAL(ns_controls_create(server, &server->controls),
           "ns_controls_create");
    server->dispatchgen = 0;
    ISC_LIST_INIT(server->dispatches);

    ISC_LIST_INIT(server->statschannels);

    server->magic = NS_SERVER_MAGIC;
    *serverp = server;
}

主要函数

run_server

调用run_server 函数启动服务器,该函数负责创建加载服务器配置,创建调度管理器、接口管理器,加载区域文件。

load_configuration 函数加载服务器配置文件、区域文件,设定监听端口,配置日志功能:
configure_server_quota 配置服务器配额(如tcp-clients,recursive-clients)
configure_view_acl 配置视图的访问控制列表
ns_listenlist_fromconfig 创建监听列表
ns_listenelt_fromconfig 创建监听列表
scan_interfaces 扫描网络接口
create_view 创建视图
configure_view 配置视图
configure_zone 配置区域
ns_add_reserved_dispatch
configure_hints 配置根服务器
configure_order 配置视图的rrset-order
configure_view_sortlist 配置视图的sortlist 排序
configure_view_dnsseckeys 配置视图的DNSSEC 密匙
load_zones 函数从磁盘读取区域配置文件。

shutdown_server

负责处理关闭服务器的过程,包括日志写入、结束统计、关闭接口管
理器、关闭区管理器(end_reserved_dispatches,ns_server_destroy)

ns_server_reload

ns_server_reloadcommand 负责处理reload 命令,调用zone_from_args 读取参数中的区域配置,调用reload 函数重新载入服务器配置,调用dns_zone_detach 函数重新载入区域配置。
reload 在载入服务器配置和区域文件时的过程与服务器启动时比较接近:
loadconfig 载入named.conf 配置
load_configuration
configure_server_quota 配置服务器配额

load_configuration

该函数处理named.conf 中的配置选项。
如果需要在named.conf 中增加一些自定义的选项, 首先修改
/lib/isccfg/namedconf.c,增加相应的选项处理规则。然后再在load_configuration 函数中增加处理该选项的代码。

/*
参数 const char *filename 为配置文件路径,例如“/etc/named.conf”
参数 ns_server_t *server 表明该server 是否为第一次进行load_configuration 操作:
参数 isc_boolean_t first_time
启动服务器时run_server 调用此函数,first_time = ISC_TRUE;
重新加载配置loadconfig 调用此函数,first_time = ISC_FALSE
*/

static isc_result_t
load_configuration(const char *filename, ns_server_t *server,isc_boolean_t first_time)
{
    ...
    cfg_obj_t *config; //配置解析器
    cfg_parser_t *parser = NULL;//配置解析结果
    ...

    cfg_aclconfctx_init(&aclconfctx);
    ISC_LIST_INIT(viewlist);

    /* Ensure exclusive access to configuration data. */
    result = isc_task_beginexclusive(server->task);
    RUNTIME_CHECK(result == ISC_R_SUCCESS);

    /*
     * Parse the global default pseudo-config file.
     */
    if (first_time) {
        CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
        RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
                      &ns_g_defaults) ==
                  ISC_R_SUCCESS);
    }

    /*
     * Parse the configuration file using the new config code.
     */
    result = ISC_R_FAILURE;
    config = NULL;

    /*
     * Unless this is lwresd with the -C option, parse the config file.
     */
    if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
        isc_log_write(ns_g_lctx,
                  NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
                  ISC_LOG_INFO, "loading configuration from '%s'",
                  filename);
                  /*   /lib/isccfg/include/isccfg/cfg.h 文件中定义了配置文件的解析器。
                cfg_parser_create 创建一个配置解析器。*/

        CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser));
        cfg_parser_setcallback(parser, directory_callback, NULL);
        result = cfg_parse_file(parser, filename, &cfg_type_namedconf,
                    &config);
    }

    /*
     * If this is lwresd with the -C option, or lwresd with no -C or -c
     * option where the above parsing failed, parse resolv.conf.
     */
    if (ns_g_lwresdonly &&
        (lwresd_g_useresolvconf ||
         (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
    {
        isc_log_write(ns_g_lctx,
                  NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
                  ISC_LOG_INFO, "loading configuration from '%s'",
                  lwresd_g_resolvconffile);
        if (parser != NULL)
            cfg_parser_destroy(&parser);
        CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser));
        result = ns_lwresd_parseeresolvconf(ns_g_mctx, parser,
                            &config);
    }
    CHECK(result);

    /*
     * Check the validity of the configuration.
     */
    CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx));

    /*
     * Fill in the maps array, used for resolving defaults.
     */
    i = 0;
    options = NULL;
    result = cfg_map_get(config, "options", &options);
    if (result == ISC_R_SUCCESS)
        maps[i++] = options;
    maps[i++] = ns_g_defaults;
    maps[i++] = NULL;

    /*
     * Set process limits, which (usually) needs to be done as root.
     */
    set_limits(maps);

    /*
     * Check if max number of open sockets that the system allows is
     * sufficiently large.  Failing this condition is not necessarily fatal,
     * but may cause subsequent runtime failures for a busy recursive
     * server.
     */
    result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks);
    if (result != ISC_R_SUCCESS)
        maxsocks = 0;
    result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
    if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
        isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                  NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
                  "max open files (%" ISC_PRINT_QUADFORMAT "u)"
                  " is smaller than max sockets (%u)",
                  nfiles, maxsocks);
    }

    /*
     * Set the number of socket reserved for TCP, stdio etc.
     */
    obj = NULL;
    result = ns_config_get(maps, "reserved-sockets", &obj);
    INSIST(result == ISC_R_SUCCESS);
    reserved = cfg_obj_asuint32(obj);
    if (maxsocks != 0) {
        if (maxsocks < 128U)            /* Prevent underflow. */
            reserved = 0;
        else if (reserved > maxsocks - 128U)    /* Minimum UDP space. */
            reserved = maxsocks - 128;
    }
    /* Minimum TCP/stdio space. */
    if (reserved < 128U)
        reserved = 128;
    if (reserved + 128U > maxsocks && maxsocks != 0) {
        isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                  NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
                  "less than 128 UDP sockets available after "
                  "applying 'reserved-sockets' and 'maxsockets'");
    }
    isc__socketmgr_setreserved(ns_g_socketmgr, reserved);

    /*
     * Configure various server options.
     */
    configure_server_quota(maps, "transfers-out", &server->xfroutquota);
    configure_server_quota(maps, "tcp-clients", &server->tcpquota);
    configure_server_quota(maps, "recursive-clients",
                   &server->recursionquota);
    if (server->recursionquota.max > 1000)
        isc_quota_soft(&server->recursionquota,
                   server->recursionquota.max - 100);
    else
        isc_quota_soft(&server->recursionquota, 0);

    CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx,
                 ns_g_mctx, &server->blackholeacl));
    if (server->blackholeacl != NULL)
        dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
                         server->blackholeacl);

    obj = NULL;
    result = ns_config_get(maps, "match-mapped-addresses", &obj);
    INSIST(result == ISC_R_SUCCESS);
    server->aclenv.match_mapped = cfg_obj_asboolean(obj);

    CHECKM(ns_statschannels_configure(ns_g_server, config, &aclconfctx),
           "configuring statistics server(s)");

    /*
     * Configure sets of UDP query source ports.  处理use-v4-udp-ports, avoid-v4-udp-ports, use-v6-udpports,
     */
    CHECKM(isc_portset_create(ns_g_mctx, &v4portset),
           "creating UDP port set");
    CHECKM(isc_portset_create(ns_g_mctx, &v6portset),
           "creating UDP port set");

    usev4ports = NULL;
    usev6ports = NULL;
    avoidv4ports = NULL;
    avoidv6ports = NULL;

    (void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports);
    if (usev4ports != NULL)
        portset_fromconf(v4portset, usev4ports, ISC_TRUE);
    else {
        CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
                           &udpport_high),
               "get the default UDP/IPv4 port range");
        if (udpport_low == udpport_high)
            isc_portset_add(v4portset, udpport_low);
        else {
            isc_portset_addrange(v4portset, udpport_low,
                         udpport_high);
        }
        isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                  NS_LOGMODULE_SERVER, ISC_LOG_INFO,
                  "using default UDP/IPv4 port range: [%d, %d]",
                  udpport_low, udpport_high);
    }
    (void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
    if (avoidv4ports != NULL)
        portset_fromconf(v4portset, avoidv4ports, ISC_FALSE);

    (void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports);
    if (usev6ports != NULL)
        portset_fromconf(v6portset, usev6ports, ISC_TRUE);
    else {
        CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
                           &udpport_high),
               "get the default UDP/IPv6 port range");
        if (udpport_low == udpport_high)
            isc_portset_add(v6portset, udpport_low);
        else {
            isc_portset_addrange(v6portset, udpport_low,
                         udpport_high);
        }
        isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                  NS_LOGMODULE_SERVER, ISC_LOG_INFO,
                  "using default UDP/IPv6 port range: [%d, %d]",
                  udpport_low, udpport_high);
    }
    (void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
    if (avoidv6ports != NULL)
        portset_fromconf(v6portset, avoidv6ports, ISC_FALSE);

    dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset);

    /*
     * Set the EDNS UDP size when we don't match a view.
     */
    obj = NULL;
    result = ns_config_get(maps, "edns-udp-size", &obj);
    INSIST(result == ISC_R_SUCCESS);
    udpsize = cfg_obj_asuint32(obj);
    if (udpsize < 512)
        udpsize = 512;
    if (udpsize > 4096)
        udpsize = 4096;
    ns_g_udpsize = (isc_uint16_t)udpsize;

    /*
     * Configure the zone manager.
     */
    obj = NULL;
    result = ns_config_get(maps, "transfers-in", &obj);
    INSIST(result == ISC_R_SUCCESS);
    dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));

    obj = NULL;
    result = ns_config_get(maps, "transfers-per-ns", &obj);
    INSIST(result == ISC_R_SUCCESS);
    dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));

    obj = NULL;
    result = ns_config_get(maps, "serial-query-rate", &obj);
    INSIST(result == ISC_R_SUCCESS);
    dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));

    /*
     * Determine which port to use for listening for incoming connections.
     */
    if (ns_g_port != 0)
        listen_port = ns_g_port;
    else
        CHECKM(ns_config_getport(config, &listen_port), "port");

    /*
     * Find the listen queue depth.
     */
    obj = NULL;
    result = ns_config_get(maps, "tcp-listen-queue", &obj);
    INSIST(result == ISC_R_SUCCESS);
    ns_g_listen = cfg_obj_asuint32(obj);
    if (ns_g_listen < 3)
        ns_g_listen = 3;

    /*
     * Configure the interface manager according to the "listen-on"
     * statement.
     */
    {
        const cfg_obj_t *clistenon = NULL;
        ns_listenlist_t *listenon = NULL;

        clistenon = NULL;
        /*
         * Even though listen-on is present in the default
         * configuration, we can't use it here, since it isn't
         * used if we're in lwresd mode.  This way is easier.
         */
        if (options != NULL)
            (void)cfg_map_get(options, "listen-on", &clistenon);
        if (clistenon != NULL) {
            result = ns_listenlist_fromconfig(clistenon,
                              config,
                              &aclconfctx,
                              ns_g_mctx,
                              &listenon);
        } else if (!ns_g_lwresdonly) {
            /*
             * Not specified, use default.
             */
            CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
                            ISC_TRUE, &listenon));
        }
        if (listenon != NULL) {
            ns_interfacemgr_setlistenon4(server->interfacemgr,
                             listenon);
            ns_listenlist_detach(&listenon);
        }
    }
    /*
     * Ditto for IPv6.
     */
    {
        const cfg_obj_t *clistenon = NULL;
        ns_listenlist_t *listenon = NULL;

        if (options != NULL)
            (void)cfg_map_get(options, "listen-on-v6", &clistenon);
        if (clistenon != NULL) {
            result = ns_listenlist_fromconfig(clistenon,
                              config,
                              &aclconfctx,
                              ns_g_mctx,
                              &listenon);
        } else if (!ns_g_lwresdonly) {
            isc_boolean_t enable;
            /*
             * Not specified, use default.
             */
            enable = ISC_TF(isc_net_probeipv4() != ISC_R_SUCCESS);
            CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
                            enable, &listenon));
        }
        if (listenon != NULL) {
            ns_interfacemgr_setlistenon6(server->interfacemgr,
                             listenon);
            ns_listenlist_detach(&listenon);
        }
    }

    /*
     * Rescan the interface list to pick up changes in the
     * listen-on option.  It's important that we do this before we try
     * to configure the query source, since the dispatcher we use might
     * be shared with an interface.
     */
    scan_interfaces(server, ISC_TRUE);

    /*
     * Arrange for further interface scanning to occur periodically
     * as specified by the "interface-interval" option.
     */
    obj = NULL;
    result = ns_config_get(maps, "interface-interval", &obj);
    INSIST(result == ISC_R_SUCCESS);
    interface_interval = cfg_obj_asuint32(obj) * 60;
    if (interface_interval == 0) {
        CHECK(isc_timer_reset(server->interface_timer,
                      isc_timertype_inactive,
                      NULL, NULL, ISC_TRUE));
    } else if (server->interface_interval != interface_interval) {
        isc_interval_set(&interval, interface_interval, 0);
        CHECK(isc_timer_reset(server->interface_timer,
                      isc_timertype_ticker,
                      NULL, &interval, ISC_FALSE));
    }
    server->interface_interval = interface_interval;

    /*
     * Configure the dialup heartbeat timer.
     */
    obj = NULL;
    result = ns_config_get(maps, "heartbeat-interval", &obj);
    INSIST(result == ISC_R_SUCCESS);
    heartbeat_interval = cfg_obj_asuint32(obj) * 60;
    if (heartbeat_interval == 0) {
        CHECK(isc_timer_reset(server->heartbeat_timer,
                      isc_timertype_inactive,
                      NULL, NULL, ISC_TRUE));
    } else if (server->heartbeat_interval != heartbeat_interval) {
        isc_interval_set(&interval, heartbeat_interval, 0);
        CHECK(isc_timer_reset(server->heartbeat_timer,
                      isc_timertype_ticker,
                      NULL, &interval, ISC_FALSE));
    }
    server->heartbeat_interval = heartbeat_interval;

    isc_interval_set(&interval, 1200, 0);
    CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
                  &interval, ISC_FALSE));

    /*
     * Configure and freeze all explicit views.  Explicit
     * views that have zones were already created at parsing
     * time, but views with no zones must be created here.对配置文件中定义的各个视图,依次创建并配置
     */
    views = NULL;
    (void)cfg_map_get(config, "view", &views);
    for (element = cfg_list_first(views);
         element != NULL;
         element = cfg_list_next(element))
    {
        const cfg_obj_t *vconfig = cfg_listelt_value(element);
        view = NULL;

        CHECK(create_view(vconfig, &viewlist, &view));
        INSIST(view != NULL);
        CHECK(configure_view(view, config, vconfig,
                     ns_g_mctx, &aclconfctx, ISC_TRUE));
        dns_view_freeze(view);
        dns_view_detach(&view);
    }

    /*
     * Make sure we have a default view if and only if there
     * were no explicit views.
     */
    if (views == NULL) {
        /*
         * No explicit views; there ought to be a default view.
         * There may already be one created as a side effect
         * of zone statements, or we may have to create one.
         * In either case, we need to configure and freeze it.
         */
        CHECK(create_view(NULL, &viewlist, &view));
        CHECK(configure_view(view, config, NULL, ns_g_mctx,
                     &aclconfctx, ISC_TRUE));
        dns_view_freeze(view);
        dns_view_detach(&view);
    }

    /*
     * Create (or recreate) the built-in views.  Currently
     * there is only one, the _bind view.
     */
    builtin_views = NULL;
    RUNTIME_CHECK(cfg_map_get(ns_g_config, "view",
                  &builtin_views) == ISC_R_SUCCESS);
    for (element = cfg_list_first(builtin_views);
         element != NULL;
         element = cfg_list_next(element))
    {
        const cfg_obj_t *vconfig = cfg_listelt_value(element);
        CHECK(create_view(vconfig, &viewlist, &view));
        CHECK(configure_view(view, config, vconfig, ns_g_mctx,
                     &aclconfctx, ISC_FALSE));
        dns_view_freeze(view);
        dns_view_detach(&view);
        view = NULL;
    }

    /*
     * Swap our new view list with the production one.
     */
    tmpviewlist = server->viewlist;
    server->viewlist = viewlist;
    viewlist = tmpviewlist;

    /*
     * Load the TKEY information from the configuration.
     */
    if (options != NULL) {
        dns_tkeyctx_t *t = NULL;
        CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
                         &t),
               "configuring TKEY");
        if (server->tkeyctx != NULL)
            dns_tkeyctx_destroy(&server->tkeyctx);
        server->tkeyctx = t;
    }

    /*
     * Bind the control port(s).
     */
    CHECKM(ns_controls_configure(ns_g_server->controls, config,
                     &aclconfctx),
           "binding control channel(s)");

    /*
     * Bind the lwresd port(s).
     */
    CHECKM(ns_lwresd_configure(ns_g_mctx, config),
           "binding lightweight resolver ports");

    /*
     * Open the source of entropy.
     */
    if (first_time) {
        obj = NULL;
        result = ns_config_get(maps, "random-device", &obj);
        if (result != ISC_R_SUCCESS) {
            isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
                      "no source of entropy found");
        } else {
            const char *randomdev = cfg_obj_asstring(obj);
            result = isc_entropy_createfilesource(ns_g_entropy,
                                  randomdev);
            if (result != ISC_R_SUCCESS)
                isc_log_write(ns_g_lctx,
                          NS_LOGCATEGORY_GENERAL,
                          NS_LOGMODULE_SERVER,
                          ISC_LOG_INFO,
                          "could not open entropy source "
                          "%s: %s",
                          randomdev,
                          isc_result_totext(result));
#ifdef PATH_RANDOMDEV
            if (ns_g_fallbackentropy != NULL) {
                if (result != ISC_R_SUCCESS) {
                    isc_log_write(ns_g_lctx,
                              NS_LOGCATEGORY_GENERAL,
                              NS_LOGMODULE_SERVER,
                              ISC_LOG_INFO,
                              "using pre-chroot entropy source "
                              "%s",
                              PATH_RANDOMDEV);
                    isc_entropy_detach(&ns_g_entropy);
                    isc_entropy_attach(ns_g_fallbackentropy,
                               &ns_g_entropy);
                }
                isc_entropy_detach(&ns_g_fallbackentropy);
            }
#endif
        }
    }

    /*
     * Relinquish root privileges.
     */
    if (first_time)
        ns_os_changeuser();

    /*
     * Check that the working directory is writable.
     */
    if (access(".", W_OK) != 0) {
        isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                  NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
                  "the working directory is not writable");
    }

    /*
     * Configure the logging system.
     *
     * Do this after changing UID to make sure that any log
     * files specified in named.conf get created by the
     * unprivileged user, not root.
     */
    if (ns_g_logstderr) {
        isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                  NS_LOGMODULE_SERVER, ISC_LOG_INFO,
                  "ignoring config file logging "
                  "statement due to -g option");
    } else {
        const cfg_obj_t *logobj = NULL;
        isc_logconfig_t *logc = NULL;

        CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
               "creating new logging configuration");

        logobj = NULL;
        (void)cfg_map_get(config, "logging", &logobj);
        if (logobj != NULL) {
            CHECKM(ns_log_configure(logc, logobj),
                   "configuring logging");
        } else {
            CHECKM(ns_log_setdefaultchannels(logc),
                   "setting up default logging channels");
            CHECKM(ns_log_setunmatchedcategory(logc),
                   "setting up default 'category unmatched'");
            CHECKM(ns_log_setdefaultcategory(logc),
                   "setting up default 'category default'");
        }

        result = isc_logconfig_use(ns_g_lctx, logc);
        if (result != ISC_R_SUCCESS) {
            isc_logconfig_destroy(&logc);
            CHECKM(result, "installing logging configuration");
        }

        isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                  NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
                  "now using logging configuration from "
                  "config file");
    }

    /*
     * Set the default value of the query logging flag depending
     * whether a "queries" category has been defined.  This is
     * a disgusting hack, but we need to do this for BIND 8
     * compatibility.
     */
    if (first_time) {
        const cfg_obj_t *logobj = NULL;
        const cfg_obj_t *categories = NULL;

        obj = NULL;
        if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
            server->log_queries = cfg_obj_asboolean(obj);
        } else {

            (void)cfg_map_get(config, "logging", &logobj);
            if (logobj != NULL)
                (void)cfg_map_get(logobj, "category",
                          &categories);
            if (categories != NULL) {
                const cfg_listelt_t *element;
                for (element = cfg_list_first(categories);
                     element != NULL;
                     element = cfg_list_next(element))
                {
                    const cfg_obj_t *catobj;
                    const char *str;

                    obj = cfg_listelt_value(element);
                    catobj = cfg_tuple_get(obj, "name");
                    str = cfg_obj_asstring(catobj);
                    if (strcasecmp(str, "queries") == 0)
                        server->log_queries = ISC_TRUE;
                }
            }
        }
    }

    obj = NULL;
    if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
        if (cfg_obj_isvoid(obj))
            ns_os_writepidfile(NULL, first_time);
        else
            ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
    else if (ns_g_lwresdonly)
        ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
    else
        ns_os_writepidfile(ns_g_defaultpidfile, first_time);

    obj = NULL;
    if (options != NULL &&
        cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
        ns_g_memstatistics = cfg_obj_asboolean(obj);
    else
        ns_g_memstatistics =
            ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);

    obj = NULL;
    if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
        ns_main_setmemstats(cfg_obj_asstring(obj));
    else if (ns_g_memstatistics)
        ns_main_setmemstats("named.memstats");
    else
        ns_main_setmemstats(NULL);

    obj = NULL;
    result = ns_config_get(maps, "statistics-file", &obj);
    INSIST(result == ISC_R_SUCCESS);
    CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
           "strdup");

    obj = NULL;
    result = ns_config_get(maps, "dump-file", &obj);
    INSIST(result == ISC_R_SUCCESS);
    CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
           "strdup");

    obj = NULL;
    result = ns_config_get(maps, "recursing-file", &obj);
    INSIST(result == ISC_R_SUCCESS);
    CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
           "strdup");

    obj = NULL;
    result = ns_config_get(maps, "version", &obj);
    if (result == ISC_R_SUCCESS) {
        CHECKM(setoptstring(server, &server->version, obj), "strdup");
        server->version_set = ISC_TRUE;
    } else {
        server->version_set = ISC_FALSE;
    }

    obj = NULL;
    result = ns_config_get(maps, "hostname", &obj);
    if (result == ISC_R_SUCCESS) {
        CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
        server->hostname_set = ISC_TRUE;
    } else {
        server->hostname_set = ISC_FALSE;
    }

    obj = NULL;
    result = ns_config_get(maps, "server-id", &obj);
    server->server_usehostname = ISC_FALSE;
    if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
        /* The parser translates "hostname" to ISC_TRUE */
        server->server_usehostname = cfg_obj_asboolean(obj);
        result = setstring(server, &server->server_id, NULL);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
    } else if (result == ISC_R_SUCCESS) {
        /* Found a quoted string */
        CHECKM(setoptstring(server, &server->server_id, obj), "strdup");
    } else {
        result = setstring(server, &server->server_id, NULL);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
    }

    obj = NULL;
    result = ns_config_get(maps, "flush-zones-on-shutdown", &obj);
    if (result == ISC_R_SUCCESS) {
        server->flushonshutdown = cfg_obj_asboolean(obj);
    } else {
        server->flushonshutdown = ISC_FALSE;
    }

    result = ISC_R_SUCCESS;

 cleanup:
    if (v4portset != NULL)
        isc_portset_destroy(ns_g_mctx, &v4portset);

    if (v6portset != NULL)
        isc_portset_destroy(ns_g_mctx, &v6portset);

    cfg_aclconfctx_destroy(&aclconfctx);

    if (parser != NULL) {
        if (config != NULL)
            cfg_obj_destroy(parser, &config);
        cfg_parser_destroy(&parser);
    }

    if (view != NULL)
        dns_view_detach(&view);

    /*
     * This cleans up either the old production view list
     * or our temporary list depending on whether they
     * were swapped above or not.
     */
    for (view = ISC_LIST_HEAD(viewlist);
         view != NULL;
         view = view_next) {
        view_next = ISC_LIST_NEXT(view, link);
        ISC_LIST_UNLINK(viewlist, view, link);
        if (result == ISC_R_SUCCESS &&
            strcmp(view->name, "_bind") != 0)
            (void)dns_zt_apply(view->zonetable, ISC_FALSE,
                       removed, view);
        dns_view_detach(&view);
    }

    /*
     * Adjust the listening interfaces in accordance with the source
     * addresses specified in views and zones.
     */
    if (isc_net_probeipv6() == ISC_R_SUCCESS)
        adjust_interfaces(server, ns_g_mctx);

    /* Relinquish exclusive access to configuration data. */
    isc_task_endexclusive(server->task);

    isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
              ISC_LOG_DEBUG(1), "load_configuration: %s",
              isc_result_totext(result));

    return (result);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值