int main(int argc, const char * const argv[]) { char c; const char *ap_confname = "httpd.conf"; const char *ngx_confname = "nginx.conf"; const char *def_server_root = NULL; const char *temp_error_log = NULL; const char *error; process_rec *process; server_rec *server_conf; apr_pool_t *pglobal; apr_pool_t *pconf; apr_pool_t *plog; /* Pool of log streams, reset _after_ each read of conf */ apr_pool_t *ptemp; /* Pool for temporary config stuff, reset often */ apr_pool_t *pcommands; /* Pool for -D, -C and -c switches */ apr_getopt_t *opt; apr_status_t rv; const char *optarg; AP_MONCONTROL(0); /* turn off profiling of startup */ process = init_process(&argc, &argv); pglobal = process->pool; pconf = process->pconf; ap_server_argv0 = process->short_name; #if APR_CHARSET_EBCDIC if (ap_init_ebcdic(pglobal) != APR_SUCCESS) { destroy_and_exit_process(process, 1); } #endif apr_pool_create(&pcommands, pglobal); apr_pool_tag(pcommands, "pcommands"); ap_server_pre_read_config = apr_array_make(pcommands, 1, sizeof(char *)); ap_server_post_read_config = apr_array_make(pcommands, 1, sizeof(char *)); ap_server_config_defines = apr_array_make(pcommands, 1, sizeof(char *)); error = ap_setup_prelinked_modules(process); if (error) { ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_EMERG, 0, NULL, "%s: %s", ap_server_argv0, error); destroy_and_exit_process(process, 1); } ap_run_rewrite_args(process); /* Maintain AP_SERVER_BASEARGS list in http_main.h to allow the MPM * to safely pass on our args from its rewrite_args() handler. */ apr_getopt_init(&opt, pcommands, process->argc, process->argv); while ((rv = apr_getopt(opt, APN_SERVER_BASEARGS, &c, &optarg)) == APR_SUCCESS) { switch (c) { case 'f': ap_confname = optarg; break; case 'o': ngx_confname = optarg; break; case 'd': def_server_root = optarg; break; case 'l': ap_show_modules(); destroy_and_exit_process(process, 0); case 'L': ap_show_directives(); destroy_and_exit_process(process, 0); case 'h': case '?': usage(process); destroy_and_exit_process(process, 0); case 'H': setconf = 1; confname = optarg; break; case 'i': defindex = 1; break; case 'G': defgzip = 1; break; case 'D': cleancfg = 1; break; case 'R': forcerm = 1; break; } } if (rv != APR_EOF || argc < 3) { if (c != 'h' && c != '?') { usage(process); } destroy_and_exit_process(process, 1); } apr_pool_create(&plog, pglobal); apr_pool_tag(plog, "plog"); apr_pool_create(&ptemp, pconf); apr_pool_tag(ptemp, "ptemp"); /** we need the real path */ char* fullpath = NULL; rv = apr_get_realpath(&fullpath, ap_confname, plog); if (rv != APR_SUCCESS){ apn_error("Apache conf file is not found " "or the given path is invalid! Exit.\n"); destroy_and_exit_process(process, 1); } ap_confname = apr_pstrdup(plog, fullpath); /* Note that we preflight the config file once * before reading it _again_ in the main loop. * This allows things, log files configuration * for example, to settle down. */ ap_server_root = def_server_root; if (!ap_server_root){ // no specify serverroot by -d in commandline. if (!ap_confname) { apn_error("Apache conf file name is null!\n"); destroy_and_exit_process(process, 1); } /** * if ap_confname is absolute path, get the prefix as serverroot. * if it is not, set the current path as serverroot. */ char* basedir; rv = apr_get_basedir(&basedir, ap_confname, process->pool); if(rv!=APR_SUCCESS){ apn_error("Apache conf file is not found " "or the given path is invalid! Exit.\n"); destroy_and_exit_process(process, 1); } ap_server_root = def_server_root = basedir; /** * Sometimes, ap_server_root should be set more intelligence. * Because of apache conf depend on the ServerRoot. * when not in localhost, maybe ServerRoot is not valid, * and here need to guess the ap_server_root. */ apn_fixed_server_root(plog); } if (temp_error_log) { ap_replace_stderr_log(process->pool, temp_error_log); } char *ngx_fullpath = NULL; rv = apr_get_realpath(&ngx_fullpath, ngx_confname, plog); if (rv == APR_SUCCESS && forcerm != 1) { apn_error("Config file exists: %s. Exit.\n", ngx_fullpath); destroy_and_exit_process(process, 1); } else { /* Create a empty nginx.conf, because mod_mime needs this file. */ apr_file_t *f; rv = apr_file_open(&f, ngx_confname, (forcerm == 1 ? APR_TRUNCATE : APR_CREATE ) |APR_APPEND|APR_WRITE, APR_OS_DEFAULT, plog); if (rv != APR_SUCCESS) { apn_error("Create file error: %s\n", ngx_fullpath); destroy_and_exit_process(process, 1); } apr_file_close(f); } /* * here just create the main server, and the vhost is not created. */ server_conf = ap_read_config(process, ptemp, ap_confname, &ap_conftree); if (!server_conf) { destroy_and_exit_process(process, 1); } /* sort hooks here to make sure pre_config hooks are sorted properly */ apr_hook_sort_all(); if (ap_run_pre_config(pconf, plog, ptemp) != OK) { ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR, 0, NULL, "Pre-configuration failed"); destroy_and_exit_process(process, 1); } /* Lijinhu added : check the configuration validation */ if (ap_conftree == NULL) { apn_error("The apache conf file is invalid! Please check it. Exit.\n"); destroy_and_exit_process(process, 1); } rv = ap_process_config_tree(server_conf, ap_conftree, process->pconf, ptemp); if (rv == OK) { /* * 1. merge server configs. * 2. merge per dir configs for each server. * 3. re-order the directorise. */ ap_fixup_virtual_hosts(pconf, server_conf); /* compile the tables and such we need to do the run-time vhost lookups */ ap_fini_vhost_config(pconf, server_conf); /* * Sort hooks again because ap_process_config_tree may have added * modules and hence hooks. This happens with mod_perl and modules * written in perl. */ apr_hook_sort_all(); ap_run_test_config(pconf, server_conf); ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "Syntax OK"); if ( ap_run_post_config(pconf, plog, ptemp, server_conf) != OK) { ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR, 0, NULL, "Failed when merge some configurations"); destroy_and_exit_process(process, 1); } /* * migrate the config to nginx conf format. * generate the conf file of nginx. */ rv = apn_migrate_to_nginx(plog, server_conf, ngx_confname); if (rv != OK) { ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "Migrate Error!"); } destroy_and_exit_process(process, 0); } return 0; /* Termination 'ok' */ }
/* 处理每个服务器策略下的指令 */ static int process_server_policy(server_policy_t *sp, server_rec *server_conf, apr_pool_t *ptemp) { apr_status_t rv; ap_directive_t *newdir; ap_directive_t *current; ap_directive_t *conftree; virt_host_t *vhost; int sname_set; char strbuf[STR_LEN_MAX]; /* 每个服务器策略建立一颗临时的配置树 */ conftree = NULL; current = NULL; /* 限制了当启用KeepAlive时,每个连接允许的请求数量。*/ newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; /* 使用服务器策略名字作为指令文件名 */ newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "MaxKeepAliveRequests"); newdir->args = apr_pstrdup(ptemp, "500"); current = ap_add_node(&conftree, current, newdir, 0); conftree = current; if (sp->work_mode == WORK_REVERSE) { /* 处理反向代理配置 */ if (sp->orig_host->proto == PROTO_HTTPS) { sprintf(strbuf, "/ https://%d.%d.%d.%d:%d/", NIPQUAD(sp->orig_host->ipaddr.s_addr), sp->orig_host->port); } else { sprintf(strbuf, "/ http://%d.%d.%d.%d:%d/", NIPQUAD(sp->orig_host->ipaddr.s_addr), sp->orig_host->port); } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_main_server, "backend host: %s", strbuf); newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "ProxyPass"); newdir->args = apr_pstrdup(ptemp, strbuf); current = ap_add_node(&conftree, current, newdir, 0); newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "ProxyPassReverse"); newdir->args = apr_pstrdup(ptemp, strbuf); current = ap_add_node(&conftree, current, newdir, 0); } else if ((sp->work_mode == WORK_BRIDGE) || (sp->work_mode == WORK_ROUTE)) { /* 处理透明代理配置 */ newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "ProxyTransparent"); newdir->args = apr_pstrdup(ptemp, "On"); current = ap_add_node(&conftree, current, newdir, 0); if (!sp->is_default) { for (sname_set = 0, vhost = sp->virt_host->next; vhost; vhost = vhost->next) { if (strlen(vhost->server_name) > 0) { newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); if (!sname_set) { newdir->directive = apr_pstrdup(ptemp, "ServerName"); sname_set = 1; } else { newdir->directive = apr_pstrdup(ptemp, "ServerAlias"); } newdir->args = apr_pstrdup(ptemp, vhost->server_name); current = ap_add_node(&conftree, current, newdir, 0); } } } newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "ProxyPreserveHost"); newdir->args = apr_pstrdup(ptemp, "On"); current = ap_add_node(&conftree, current, newdir, 0); } else if (sp->work_mode == WORK_OFFLINE) { /* 处理离线模式配置 */ if (!sp->is_default) { for (sname_set = 0, vhost = sp->virt_host->next; vhost; vhost = vhost->next) { if (strlen(vhost->server_name) > 0) { newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); if (!sname_set) { newdir->directive = apr_pstrdup(ptemp, "ServerName"); sname_set = 1; } else { newdir->directive = apr_pstrdup(ptemp, "ServerAlias"); } newdir->args = apr_pstrdup(ptemp, vhost->server_name); current = ap_add_node(&conftree, current, newdir, 0); } } } } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_main_server, "work mode error"); return DECLINED; } /* 配置防护引擎 */ if (BitGet(sp->opt_flags, ENGINE_FLAG)) { switch (sp->engine) { case BLOCK_OFF: sprintf(strbuf, "Off"); break; case BLOCK_DET: sprintf(strbuf, "DetectionOnly"); break; case BLOCK_ON: sprintf(strbuf, "On"); break; default: sprintf(strbuf, "On"); break; } newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "SecRuleEngine"); newdir->args = apr_pstrdup(ptemp, strbuf); current = ap_add_node(&conftree, current, newdir, 0); } /* 配置审核日志 */ if (BitGet(sp->audit_set, ACCESS_LOG)) { if (BitGet(sp->audit_log, ACCESS_LOG)) { newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "SecAccessLog"); newdir->args = apr_pstrdup(ptemp, "On"); current = ap_add_node(&conftree, current, newdir, 0); } else { newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "SecAccessLog"); newdir->args = apr_pstrdup(ptemp, "Off"); current = ap_add_node(&conftree, current, newdir, 0); } } if (BitGet(sp->audit_set, ATTACK_LOG)) { if (BitGet(sp->audit_log, ATTACK_LOG)) { newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "SecAttackLog"); newdir->args = apr_pstrdup(ptemp, "On"); current = ap_add_node(&conftree, current, newdir, 0); if (sp->atlog_lev) { sprintf(strbuf, "%d", sp->atlog_lev); newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; /* 使用服务器策略名字作为指令文件名 */ newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "SecAttackLogLevel"); newdir->args = apr_pstrdup(ptemp, strbuf); current = ap_add_node(&conftree, current, newdir, 0); } } else { newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; /* 使用服务器策略名字作为指令文件名 */ newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "SecAttackLog"); newdir->args = apr_pstrdup(ptemp, "Off"); current = ap_add_node(&conftree, current, newdir, 0); } } /* 离线模式不配置缓存模块 */ if (sp->cache_root && sp->work_mode != WORK_OFFLINE) { newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; /* 使用服务器策略名字作为指令文件名 */ newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "CacheEnable"); newdir->args = apr_pstrdup(ptemp, "disk /"); current = ap_add_node(&conftree, current, newdir, 0); newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "CacheRoot"); newdir->args = apr_pstrdup(ptemp, sp->cache_root); current = ap_add_node(&conftree, current, newdir, 0); } else if (sp->cache_root && sp->work_mode == WORK_OFFLINE) { newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = sp->name; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "CacheDisable"); newdir->args = apr_pstrdup(ptemp, "/"); current = ap_add_node(&conftree, current, newdir, 0); } /* 配置安全策略和规则集 */ rv = process_security_rule(sp, current, conftree, ptemp); if (rv != OK) { return DECLINED; } #if SHOW_SECURITY_RULE /* 指令下发调试 */ conftree_traverse(conftree); #endif if (conftree) { rv = ap_process_config_tree(server_conf, conftree, sp->pvhost, ptemp); } return rv; }
/** * 离线模式配置初始化 */ AP_DECLARE(int) ap_offline_configure(void) { int i; apr_status_t rv; ap_directive_t *newdir; ap_directive_t *current; ap_directive_t *conftree; apr_pool_t *ptemp; /* Pool for temporary config stuff, reset often */ char strbuf[STR_LEN_MAX]; if (ap_off_iface == 0) { return DONE; } /* 配置处理过程中的临时数据放在临时内存池里面 */ apr_pool_create(&ptemp, pconf); apr_pool_tag(ptemp, "ptemp"); rv = OK; /* 建立一颗临时的配置树 */ conftree = NULL; current = conftree; newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = "offline mode"; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "OfflineEngine"); newdir->args = apr_pstrdup(ptemp, "On"); current = ap_add_node(&conftree, current, newdir, 0); conftree = current; /* 设定监听端口 */ for (i = 0; i < OFFLINE_INTF_NUM; i++) { if (BitGet(ap_off_iface, i + 1)) { sprintf(strbuf, "eth%d", i); newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = "offline mode"; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "OfflineEthName"); newdir->args = apr_pstrdup(ptemp, strbuf); current = ap_add_node(&conftree, current, newdir, 0); } } newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = "offline mode"; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, "OfflineLogLevel"); newdir->args = apr_pstrdup(ptemp, "fatal"); current = ap_add_node(&conftree, current, newdir, 0); /* 指令下发调试 */ for (current = conftree; current != NULL; current = current->next) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_main_server, "%s: line[%d] directive[%s] args[%s]", current->filename, current->line_num, current->directive, current->args); } if (conftree) { rv = ap_process_config_tree(ap_main_server, conftree, pconf, ptemp); } apr_pool_destroy(ptemp); return rv; }
/********************************************************** * 黑白名单相关的处理函数 **********************************************************/ AP_DECLARE(int) ap_access_list_handle(int lst) { apr_status_t rv; ap_directive_t *newdir; ap_directive_t *current; ap_directive_t *conftree; apr_array_header_t *acl_config; apr_pool_t *ptemp; char *cmd_name; const char **cmd_args; if ((lst < IP_BLACK) || (lst > ALL_LIST)) { return DECLINED; } /* 配置处理过程中的临时数据放在临时内存池里面 */ apr_pool_create(&ptemp, pconf); apr_pool_tag(ptemp, "ptemp"); /* 读取黑白名单的指令 */ acl_config = apr_array_make(ptemp, 1, sizeof(char *)); rv = convert_access_list_query(lst, &acl_config); if (rv != OK) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "query access list %d error", lst); return DECLINED; } /* 建立一颗临时的配置树 */ conftree = NULL; current = conftree; while (1) { cmd_args = (const char **)apr_array_pop(acl_config); if (!cmd_args) { break; } cmd_name = ap_getword_conf(ptemp, cmd_args); newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t)); newdir->filename = "access list"; newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1); newdir->directive = apr_pstrdup(ptemp, cmd_name); newdir->args = apr_pstrdup(ptemp, *cmd_args); current = ap_add_node(&conftree, current, newdir, 0); if (conftree == NULL && current != NULL) { conftree = current; } } /* 指令下发调试 */ for (current = conftree; current != NULL; current = current->next) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_main_server, "%s: line[%d] directive[%s] args[%s]", current->filename, current->line_num, current->directive, current->args); } /* 处理黑白名单的指令 */ if (conftree) { rv = ap_process_config_tree(ap_main_server, conftree, pconf, ptemp); } apr_pool_destroy(ptemp); return rv; }