wazuh-modules-sca-scan

 sca模块主函数wm_sca_main -> wm_sca_start

 检查policy文件中的每一个项目wm_sca_check_policy

static int wm_sca_check_policy(const cJSON * const policy, const cJSON * const checks, OSHash *global_check_list)
{if(!policy) {return 1;}const cJSON * const id = cJSON_GetObjectItem(policy, "id");if(!id) {mwarn("Field 'id' not found in policy header.");return 1;}if(!id->valuestring){mwarn("Invalid format for field 'id'");return 1;}char *coincident_policy_file;if((coincident_policy_file = OSHash_Get(global_check_list,id->valuestring)), coincident_policy_file) {mwarn("Found duplicated policy ID: %s. File '%s' contains the same ID.", id->valuestring, coincident_policy_file);return 1;}const cJSON * const name = cJSON_GetObjectItem(policy, "name");if(!name) {mwarn("Field 'name' not found in policy header.");return 1;}if(!name->valuestring){mwarn("Invalid format for field 'name'");return 1;}const cJSON * const file = cJSON_GetObjectItem(policy, "file");if(!file) {mwarn("Field 'file' not found in policy header.");return 1;}if(!file->valuestring){mwarn("Invalid format for field 'file'");return 1;}const cJSON * const description = cJSON_GetObjectItem(policy, "description");if(!description) {mwarn("Field 'description' not found in policy header.");return 1;}const cJSON * const regex_type = cJSON_GetObjectItem(policy, "regex_type");if(!regex_type) {mdebug1("Field 'regex_type' not found in policy header. The OS_REGEX engine shall be used.");}if(!description->valuestring) {mwarn("Invalid format for field 'description'");return 1;}// Check for policy rules with duplicated IDs */if (!checks) {mwarn("Section 'checks' not found.");return 1;}int *read_id;os_calloc(1, sizeof(int), read_id);read_id[0] = 0;const cJSON *check;cJSON_ArrayForEach(check, checks) {const cJSON * const check_id = cJSON_GetObjectItem(check, "id");if (check_id == NULL) {mwarn("Check ID not found.");free(read_id);return 1;}if (check_id->valueint <= 0) {// Invalid IDmwarn("Invalid check ID: %d", check_id->valueint);free(read_id);return 1;}char *coincident_policy;char *key_id;size_t key_length = snprintf(NULL, 0, "%d", check_id->valueint);os_malloc(key_length + 1, key_id);snprintf(key_id, key_length + 1, "%d", check_id->valueint);if((coincident_policy = (char *)OSHash_Get(global_check_list, key_id)), coincident_policy){// Invalid IDmwarn("Found duplicated check ID: %d. First appearance at policy '%s'", check_id->valueint, coincident_policy);os_free(key_id);os_free(read_id);return 1;}os_free(key_id);int i;for (i = 0; read_id[i] != 0; i++) {if (check_id->valueint == read_id[i]) {// Duplicated IDmwarn("Found duplicated check ID: %d", check_id->valueint);free(read_id);return 1;}}os_realloc(read_id, sizeof(int) * (i + 2), read_id);read_id[i] = check_id->valueint;read_id[i + 1] = 0;const cJSON * const rules = cJSON_GetObjectItem(check, "rules");if (rules == NULL) {mwarn("Invalid check %d: no rules found.", check_id->valueint);free(read_id);return 1;}int rules_n = 0;const cJSON *rule;cJSON_ArrayForEach(rule, rules) {if (!rule->valuestring) {mwarn("Invalid check %d: Empty rule.", check_id->valueint);free(read_id);return 1;}char *valuestring_ref = rule->valuestring;valuestring_ref += 4 * (!strncmp(valuestring_ref, "NOT ", 4) || !strncmp(valuestring_ref, "not ", 4));switch (*valuestring_ref) {
#ifdef WIN32case 'r':
#endifcase 'f':case 'd':case 'p':case 'c':break;case '\0':mwarn("Invalid check %d: Empty rule.", check_id->valueint);free(read_id);return 1;default:mwarn("Invalid check %d: Invalid rule format.", check_id->valueint);free(read_id);return 1;}rules_n++;if (rules_n > 255) {free(read_id);mwarn("Invalid check %d: Maximum number of rules is 255.", check_id->valueint);return 1;}}if (rules_n == 0) {mwarn("Invalid check %d: no rules found.", check_id->valueint);free(read_id);return 1;}}char *policy_file = NULL;os_strdup(file->valuestring, policy_file);const int id_add_retval = OSHash_Add(global_check_list, id->valuestring, policy_file);if (id_add_retval == 0){os_free(policy_file);os_free(read_id);merror_exit("(1102): Could not acquire memory");}if (id_add_retval == 1){merror("Error validating duplicated ID. Policy %s in file %s is duplicated", id->valuestring, policy_file);os_free(policy_file);os_free(read_id);return 1;}int i;for (i = 0; read_id[i] != 0; ++i) {char *policy_id = NULL;os_strdup(id->valuestring, policy_id);const int check_add_retval = OSHash_Numeric_Add_ex(global_check_list, read_id[i], policy_id);if (check_add_retval == 0){os_free(policy_id);os_free(read_id);merror_exit("(1102): Could not acquire memory");}if (check_add_retval == 1){merror("Error validating duplicated ID. Check %s in policy %s is duplicated", id->valuestring, policy_id);os_free(policy_id);os_free(read_id);return 1;}}os_free(read_id);return 0;
}

policy文件中的具体rules项目,其中规则之一:

# 1.1.1.3 udf: filesystem- id: 6002title: "Ensure mounting of udf filesystems is disabled"description: "The udf filesystem type is the universal disk format used to implement ISO/IEC 13346 and ECMA-167 specifications. This is an open vendor filesystem type for data storage on a broad range of media. This filesystem type is necessary to support writing DVDs and newer optical disc formats."rationale: "Removing support for unneeded filesystem types reduces the local attack surface of the system. If this filesystem type is not needed, disable it."remediation: "Edit or create the file /etc/modprobe.d/CIS.conf and add the following line: install udf /bin/true. Run the following command to unload the udf module: rmmod udf"compliance:- cis: ["1.1.1.3"]- cis_csc: ["5.1"]- pci_dss: ["2.2.5"]- tsc: ["CC6.3"]references:- AJ Lewis, "LVM HOWTO", https://tldp.org/HOWTO/LVM-HOWTO/condition: allrules:- 'c:modprobe -n -v udf -> r:install /bin/true|Module udf not found'- 'not c:lsmod -> r:udf'

rules中的每一项是r (读取), f,d,p,c,not,NOT开头  "->"表示前一个动作之后的接着的下一个动作,或者条件

 sca扫描核心函数

/*
Rules that match always return 1, and the other way arround.Rule aggregators logic:##########################################################ALL:r_1 -f -> r:123...r_n -f -> r:234For an ALL to succeed, every rule shall return 1, in other words,|  = n -> ALL = RETURN_FOUND
SUM(r_i, 0, n) || != n -> ALL = RETURN_NOT_FOUND##########################################################ANY:r_1 -f -> r:123...r_n -f -> r:234For an ANY to succeed, a rule shall return 1, in other words,| > 0 -> ANY = RETURN_FOUND
SUM(r_i, 0, n) || = 0 -> ANY = RETURN_NOT_FOUND##########################################################NONE:r_1 -f -> r:123...r_n -f -> r:234For a NONE to succeed, all rules shall return RETURN_NOT_FOUND, in other words,|  > 0 -> NONE = RETURN_NOT_FOUND
SUM(r_i, 0, n) ||  = 0 -> NONE = RETURN_FOUND##########################################################ANY and NONE aggregators are complementary.*/static int wm_sca_do_scan(cJSON * checks,OSStore * vars,wm_sca_t * data,int id,cJSON * policy,int requirements_scan,int cis_db_index,unsigned int remote_policy,int first_scan,int * checks_number,char ** sorted_variables,char * policy_engine)
{int type = 0;char buf[OS_SIZE_1024 + 2];char final_file[2048 + 1];char *reason = NULL;int ret_val = 0;OSList *p_list = NULL;/* Initialize variables */memset(buf, '\0', sizeof(buf));memset(final_file, '\0', sizeof(final_file));int check_count = 0;cJSON *check = NULL;cJSON_ArrayForEach(check, checks) {char _check_id_str[50];if (requirements_scan) {snprintf(_check_id_str, sizeof(_check_id_str), "Requirements check");} else {const cJSON * const c_id = cJSON_GetObjectItem(check, "id");if (!c_id || !c_id->valueint) {merror("Skipping check. Check ID is invalid. Offending check number: %d", check_count);ret_val = 1;continue;}snprintf(_check_id_str, sizeof(_check_id_str), "id: %d", c_id->valueint);}const cJSON * const c_title = cJSON_GetObjectItem(check, "title");if (!c_title || !c_title->valuestring) {merror("Skipping check with %s: Check name is invalid.", _check_id_str);if (requirements_scan) {ret_val = 1;goto clean_return;}continue;}const cJSON * const c_condition = cJSON_GetObjectItem(check, "condition");if (!c_condition || !c_condition->valuestring) {merror("Skipping check '%s: %s': Check condition not found.", _check_id_str, c_title->valuestring);if (requirements_scan) {ret_val = 1;goto clean_return;}continue;}int condition = 0;wm_sca_set_condition(c_condition->valuestring, &condition);if (condition == WM_SCA_COND_INV) {merror("Skipping check '%s: %s': Check condition (%s) is invalid.",_check_id_str, c_title->valuestring, c_condition->valuestring);if (requirements_scan) {ret_val = 1;goto clean_return;}continue;}int g_found = RETURN_NOT_FOUND;if ((condition & WM_SCA_COND_ANY) || (condition & WM_SCA_COND_NON)) {/* aggregators ANY and NONE break by matching, so they shall return NOT_FOUND if they never break */g_found = RETURN_NOT_FOUND;} else if (condition & WM_SCA_COND_ALL) {/* aggregator ALL breaks the moment a rule does not match. If it doesn't break, all rules have matched */g_found = RETURN_FOUND;}mdebug1("Beginning evaluation of check %s '%s'", _check_id_str, c_title->valuestring);mdebug1("Rule aggregation strategy for this check is '%s'", c_condition->valuestring);mdebug2("Initial rule-aggregator value por this type of rule is '%d'",  g_found);mdebug1("Beginning rules evaluation.");const cJSON *const rules = cJSON_GetObjectItem(check, "rules");if (!rules) {merror("Skipping check %s '%s': No rules found.", _check_id_str, c_title->valuestring);if (requirements_scan) {ret_val = 1;goto clean_return;}continue;}w_expression_t * regex_engine = NULL;cJSON * engine = cJSON_GetObjectItem(check, "regex_type");if (engine) {if (strcmp(PCRE2_STR, cJSON_GetStringValue(engine)) == 0) {w_calloc_expression_t(&regex_engine, EXP_TYPE_PCRE2);} else {w_calloc_expression_t(&regex_engine, EXP_TYPE_OSREGEX);}} else {if(strcmp(PCRE2_STR, policy_engine) == 0) {w_calloc_expression_t(&regex_engine, EXP_TYPE_PCRE2);} else {w_calloc_expression_t(&regex_engine, EXP_TYPE_OSREGEX);}}mdebug1("SCA will use '%s' engine to check the rules.", w_expression_get_regex_type(regex_engine));char *rule_cp = NULL;const cJSON *rule_ref;cJSON_ArrayForEach(rule_ref, rules) {/* this free is responsible of freeing the copy of the previous rule ifthe loop 'continues', i.e, does not reach the end of its block. */os_free(rule_cp);if(!rule_ref->valuestring) {mdebug1("Field 'rule' must be a string.");ret_val = 1;os_free(regex_engine);goto clean_return;}mdebug1("Considering rule: '%s'", rule_ref->valuestring);os_strdup(rule_ref->valuestring, rule_cp);char *rule_cp_ref = NULL;#ifdef WIN32char expanded_rule[2048] = {0};ExpandEnvironmentStrings(rule_cp, expanded_rule, 2048);rule_cp_ref = expanded_rule;mdebug2("Rule after variable expansion: '%s'", rule_cp_ref);#elserule_cp_ref = rule_cp;#endifint rule_is_negated = 0;if (rule_cp_ref &&(strncmp(rule_cp_ref, "NOT ", 4) == 0 ||strncmp(rule_cp_ref, "not ", 4) == 0)){mdebug2("Rule is negated.");rule_is_negated = 1;rule_cp_ref += 4;}/* Get value to look for. char *value is a referenceto rule_cp memory. Do not release value!  */char *value = wm_sca_get_value(rule_cp_ref, &type);if (value == NULL) {merror("Invalid rule: '%s'. Skipping policy.", rule_ref->valuestring);os_free(rule_cp);ret_val = 1;os_free(regex_engine);goto clean_return;}int found = RETURN_NOT_FOUND;if (type == WM_SCA_TYPE_FILE) {/* Check files */char *pattern = wm_sca_get_pattern(value);char *rule_location = NULL;char *aux = NULL;os_strdup(value, rule_location);/* If any, replace the variables by their respective values */if (sorted_variables) {int i = 0;for (i = 0; sorted_variables[i]; i++) {if (strstr(rule_location, sorted_variables[i])) {mdebug2("Variable '%s' found at rule '%s'. Replacing it.", sorted_variables[i], rule_location);aux = wstr_replace(rule_location, sorted_variables[i], OSStore_Get(vars, sorted_variables[i]));os_free(rule_location);rule_location = aux;if (!rule_location) {merror("Invalid variable replacement: '%s'. Skipping check.", sorted_variables[i]);break;}mdebug2("Variable replaced: '%s'", rule_location);}}}if (!rule_location) {continue;}const int result = wm_sca_check_file_list(rule_location, pattern, &reason, regex_engine);if (result == RETURN_FOUND || result == RETURN_INVALID) {found = result;}char _b_msg[OS_SIZE_1024 + 1];_b_msg[OS_SIZE_1024] = '\0';snprintf(_b_msg, OS_SIZE_1024, " File: %s", rule_location);append_msg_to_vm_scat(data, _b_msg);os_free(rule_location);} else if (type == WM_SCA_TYPE_COMMAND) {/* Check command output */char *pattern = wm_sca_get_pattern(value);char *rule_location = NULL;char *aux = NULL;os_strdup(value, rule_location);if (!data->remote_commands && remote_policy) {mwarn("Ignoring check for policy '%s'. The internal option 'sca.remote_commands' is disabled.", cJSON_GetObjectItem(policy, "name")->valuestring);if (reason == NULL) {os_malloc(snprintf(NULL, 0, "Ignoring check for running command '%s'. The internal option 'sca.remote_commands' is disabled", rule_location) + 1, reason);sprintf(reason, "Ignoring check for running command '%s'. The internal option 'sca.remote_commands' is disabled", rule_location);}found = RETURN_INVALID;} else {/* If any, replace the variables by their respective values */if (sorted_variables) {int i = 0;for (i = 0; sorted_variables[i]; i++) {if (strstr(rule_location, sorted_variables[i])) {mdebug2("Variable '%s' found at rule '%s'. Replacing it.", sorted_variables[i], rule_location);aux = wstr_replace(rule_location, sorted_variables[i], OSStore_Get(vars, sorted_variables[i]));os_free(rule_location);rule_location = aux;if (!rule_location) {merror("Invalid variable: '%s'. Skipping check.", sorted_variables[i]);break;}mdebug2("Variable replaced: '%s'", rule_location);}}}if (!rule_location) {continue;}mdebug2("Running command: '%s'", rule_location);const int val = wm_sca_read_command(rule_location, pattern, data, &reason, regex_engine);if (val == RETURN_FOUND) {mdebug2("Command output matched.");found = RETURN_FOUND;} else if (val == RETURN_INVALID){mdebug2("Command output did not match.");found = RETURN_INVALID;}}char _b_msg[OS_SIZE_1024 + 1];_b_msg[OS_SIZE_1024] = '\0';snprintf(_b_msg, OS_SIZE_1024, " Command: %s", rule_location);append_msg_to_vm_scat(data, _b_msg);os_free(rule_location);} else if (type == WM_SCA_TYPE_DIR) {/* Check directory */mdebug2("Processing directory rule '%s'", value);char * const file = wm_sca_get_pattern(value);char *rule_location = NULL;char *aux = NULL;os_strdup(value, rule_location);/* If any, replace the variables by their respective values */if (sorted_variables) {int i = 0;for (i = 0; sorted_variables[i]; i++) {if (strstr(rule_location, sorted_variables[i])) {mdebug2("Variable '%s' found at rule '%s'. Replacing it.", sorted_variables[i], rule_location);aux = wstr_replace(rule_location, sorted_variables[i], OSStore_Get(vars, sorted_variables[i]));os_free(rule_location);rule_location = aux;if (!rule_location) {merror("Invalid variable: '%s'. Skipping check.", sorted_variables[i]);break;}mdebug2("Variable replaced: '%s'", rule_location);}}}if (!rule_location) {continue;}char * const pattern = wm_sca_get_pattern(file);found = wm_sca_check_dir_list(data, rule_location, file, pattern, &reason, regex_engine);mdebug2("Check directory rule result: %d", found);os_free(rule_location);} else if (type == WM_SCA_TYPE_PROCESS) {/* Check process existence */if (!p_list) {/* Lazy evaluation */p_list = w_os_get_process_list();}mdebug2("Checking process: '%s'", value);if (wm_sca_check_process_is_running(p_list, value, &reason, regex_engine)) {mdebug2("Process found.");found = RETURN_FOUND;} else {mdebug2("Process not found.");}char _b_msg[OS_SIZE_1024 + 1];_b_msg[OS_SIZE_1024] = '\0';snprintf(_b_msg, OS_SIZE_1024, " Process: %s", value);append_msg_to_vm_scat(data, _b_msg);}#ifdef WIN32else if (type == WM_SCA_TYPE_REGISTRY) {/* Check windows registry */char * const entry = wm_sca_get_pattern(value);char * const pattern = wm_sca_get_pattern(entry);found = wm_sca_is_registry(value, entry, pattern, &reason, regex_engine);char _b_msg[OS_SIZE_1024 + 1];_b_msg[OS_SIZE_1024] = '\0';snprintf(_b_msg, OS_SIZE_1024, " Registry: %s", value);append_msg_to_vm_scat(data, _b_msg);}#endif/* Rule result processing */if (found != RETURN_INVALID) {found = rule_is_negated ^ found;}mdebug1("Result for rule '%s': %d", rule_ref->valuestring, found);if (((condition & WM_SCA_COND_ALL) && found == RETURN_NOT_FOUND) ||((condition & WM_SCA_COND_ANY) && found == RETURN_FOUND) ||((condition & WM_SCA_COND_NON) && found == RETURN_FOUND)){g_found = found;mdebug1("Breaking from rule aggregator '%s' with found = %d", c_condition->valuestring, g_found);break;}if (found == RETURN_INVALID) {/* Rules that agreggate by ANY are the only that can success after an INVALIDOn the other hand ALL and NONE agregators can fail after an INVALID. */g_found = found;mdebug1("Rule evaluation returned INVALID. Continuing.");}}if ((condition & WM_SCA_COND_NON) && g_found != RETURN_INVALID) {g_found = !g_found;}mdebug1("Result for check %s '%s' -> %d", _check_id_str, c_title->valuestring, g_found);if (g_found != RETURN_INVALID) {os_free(reason);}/* if the loop breaks, rule_cp shall be released.Also frees the the memory reserved on the last iteration */os_free(rule_cp);/* Determine if requirements are satisfied */if (requirements_scan) {/*  return value for requirement scans is the inverse of the result,unless the result is INVALID */ret_val = g_found == RETURN_INVALID ? 1 : !g_found;int i;for (i=0; data->alert_msg[i]; i++){free(data->alert_msg[i]);data->alert_msg[i] = NULL;}w_free_expression_t(&regex_engine);goto clean_return;}/* Event construction */const char failed[] = "failed";const char passed[] = "passed";const char invalid[] = ""; //NOT AN ERROR!const char *message_ref = NULL;if (g_found == RETURN_NOT_FOUND) {wm_sca_summary_increment_failed();message_ref = failed;} else if (g_found == RETURN_FOUND) {wm_sca_summary_increment_passed();message_ref = passed;} else {wm_sca_summary_increment_invalid();message_ref = invalid;if (reason == NULL) {os_malloc(snprintf(NULL, 0, "Unknown reason") + 1, reason);sprintf(reason, "Unknown reason");mdebug1("A check returned INVALID for an unknown reason.");}}cJSON *event = wm_sca_build_event(check, policy, data->alert_msg, id, message_ref, reason);if (event) {/* Alert if necessary */if(!cis_db_for_hash[cis_db_index].elem[check_count]) {os_realloc(cis_db_for_hash[cis_db_index].elem, sizeof(cis_db_info_t *) * (check_count + 2), cis_db_for_hash[cis_db_index].elem);cis_db_for_hash[cis_db_index].elem[check_count] = NULL;cis_db_for_hash[cis_db_index].elem[check_count + 1] = NULL;}if (wm_sca_check_hash(cis_db[cis_db_index], message_ref, check, event, check_count, cis_db_index) && !first_scan) {wm_sca_send_event_check(data,event);}check_count++;cJSON_Delete(event);} else {merror("Error constructing event for check: %s. Set debug mode for more information.", c_title->valuestring);ret_val = 1;}int i;for (i=0; data->alert_msg[i]; i++){free(data->alert_msg[i]);data->alert_msg[i] = NULL;}os_free(reason);w_free_expression_t(&regex_engine);}*checks_number = check_count;/* Clean up memory */
clean_return:os_free(reason);w_del_plist(p_list);return ret_val;
}

迭代每一个检查项cJSON_ArrayForEach(check, checks)

/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/64337.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于单片机的智能窗帘(论文+源码)

1.系统设计 本课题智能窗帘系统的设计主要包括STM32单片机主控模块&#xff0c;光照检测模块&#xff0c;窗帘控制模块&#xff0c;键盘控制模块&#xff0c;显示模块和时钟模块等几个部分。总体设计框图如图2.1所示&#xff0c;其可以实现对当前光照强度的实时检测&#xff0…

Fastdfs V6.12.1集群部署(arm/x86均可用)

文章目录 一、 Fastdfs 介绍二、部署 信息三、步骤tracker/storage 机器的 compose 内容storage 机器的 composetracker 与 storage 启动目录层级与配置文件测试测试集群扩容与缩减注意事项 一、 Fastdfs 介绍 FastDFS 是一款高性能的分布式文件系统&#xff0c;特别适合用于存…

零基础开始学习鸿蒙开发-基础页面的设计

目录 1.样例图 2.逐项分析 2.1 头顶布局分析&#xff1a;首先我们要把第一行的图标绘制出来&#xff0c;一个左一个右&#xff0c;很明显&#xff0c;需要放在一个Row容器中&#xff0c;具体代码如下&#xff1a; 2.2 和头像同一行的布局&#xff0c;需要注意的是&#xff0c…

如何用细节提升用户体验?

前端给用户反馈是提升用户体验的重要部分&#xff0c;根据场景选择不同的方式可以有效地提升产品的易用性和用户满意度。以下是常见的方法&#xff1a; 1. 视觉反馈 用户执行了某些操作后&#xff0c;需要即时确认操作结果。例如&#xff1a;按钮点击、数据提交、页面加载等。…

[数据结构#2] 图(1) | 概念 | 邻接矩阵 | 邻接表 | 模拟

图是由顶点集合及顶点间的关系&#xff08;边&#xff09;组成的数据结构&#xff0c;可用 G ( V , E ) G(V,E) G(V,E)表示&#xff0c;其中&#xff1a; 顶点集合 V V V: V { x ∣ x ∈ 某数据对象集 } V\{x|x\in\text{某数据对象集}\} V{x∣x∈某数据对象集}&#xff0c;…

学习maven(maven 项目模块化,继承,聚合)

前言 本篇博客的核心&#xff1a;理解maven 项目模块化&#xff0c;继承&#xff0c;聚合 的含义 maven 项目模块化 含义 maven项目模块化&#xff1a;使用maven 构建项目&#xff0c;管理项目的方式&#xff0c;我们可以将maven项目根据内在的关系拆分成很多个小项目【模块】…

【OJ题解】最长回文子串

个人主页: 起名字真南的CSDN博客 个人专栏: 【数据结构初阶】 &#x1f4d8; 基础数据结构【C语言】 &#x1f4bb; C语言编程技巧【C】 &#x1f680; 进阶C【OJ题解】 &#x1f4dd; 题解精讲 目录 **题目链接****解题思路****1. 初步判断****2. 回文子串性质****3. 判断是…

EMQX 可观测性最佳实践

EMQX 介绍 EMQX 是一款开源、高度可伸缩、高可用的分布式 MQTT 消息服务器&#xff0c;同时也支持 CoAP/LwM2M 等一站式 IoT 协议接入。以下是 EMQX 的一些主要特点和功能&#xff1a; 海量连接与高并发&#xff1a;EMQX 能够处理千万级别的并发客户端&#xff0c;支持大规模…

kubeadm_k8s_v1.31高可用部署教程

kubeadm_k8s_v1.31高可用部署教程 实验环境部署拓扑图**署架构方案****Load Balance****Control plane node****Worker node****资源分配&#xff08;8台虚拟机&#xff09;**集群列表 前置准备关闭swap开启ipv4转发更多设置 1、Verify the MAC address and product_uuid are u…

mysql flink cdc 实时数据抓取

背景 通过监控mysql日志&#xff0c;获取表字段更新&#xff0c;用来做实时展示。 使用技术&#xff1a;Flink CDC Flink CDC 基于数据库日志的 Change Data Caputre 技术&#xff0c;实现了全量和增量的一体化读取能力&#xff0c;并借助 Flink 优秀的管道能力和丰富的上下游…

element plus el-select修改后缀图标

<el-selectv-model"value"placeholder"请选择工点"size"large":teleported"false":suffix-icon"CaretBottom"style"width: 100px"><el-optionv-for"item in options":key"item.value&quo…

自动驾驶控制与规划——Project 2: 车辆横向控制

目录 零、任务介绍一、环境配置二、算法三、代码实现四、效果展示 零、任务介绍 补全src/ros-bridge/carla_shenlan_projects/carla_shenlan_stanley_pid_controller/src/stanley_controller.cpp中的TODO部分。 一、环境配置 上一次作业中没有配置docker使用gpu&#xff0c;…

Qt6开发自签名证书的https代理服务器

目标&#xff1a;制作一个具备类似Fiddler、Burpsuit、Wireshark的https协议代理抓包功能&#xff0c;但是集成到自己的app内&#xff0c;这样无需修改系统代理设置&#xff0c;使用QWebengineview通过自建的代理服务器&#xff0c;即可实现https包的实时监测、注入等自定义功能…

Windows如何安装Php 7.4

一、进入官网&#xff0c;选择其他版本 https://windows.php.net/download/ 二、配置环境变量 将解压后的php 路径在系统环境变量中配置一下 cmd 后输入 php-v

ensp 静态路由配置

A公司有广州总部、重庆分部和深圳分部3个办公地点&#xff0c;各分部与总部之间使用路由器互联。广州、重庆、深圳的路由器分别为R1、R2、R3&#xff0c;为路由器配置静态路由&#xff0c;使所有计算机能够互相访问&#xff0c;实训拓扑图如图所示 绘制拓扑图 给pc机配置ip地址…

红米Note 9 Pro5G刷LineageOS

LineageOS介绍 LineageOS 是一个基于 Android 的开源操作系统&#xff0c;是面向智能手机和平板电脑等设备的替代性操作系统。它是 CyanogenMod 的继承者&#xff0c;而 CyanogenMod 是曾经非常受欢迎的一个第三方 Android 定制 ROM。 在 2016 年&#xff0c;CyanogenMod 项目因…

ECharts实现数据可视化入门详解

文章目录 ECharts实现数据可视化入门详解一、引言二、基础配置1.1、代码示例 三、动态数据与交互2.1、代码示例 四、高级用法1、多图表组合1.1、在同一容器中绘制多个图表1.2、创建多个容器并分别初始化 ECharts 实例1.3、实现多图联动 五、总结 ECharts实现数据可视化入门详解…

盲盒3.0版h5版-可打包app-新优化版紫色版

整体界面ui美观大气&#xff0c;盲盒项目也是一直比较热门的&#xff0c;各大平台一直自己也有做。 感兴趣的小伙伴可以搭建做自己的项目。盲盒项目的利润率还是很大的。

MacbookPro M1 安装Hive

前提注意⚠️⚠️⚠️ 1&#xff09;在安装Hive前确实需要安装MySQL&#xff0c;因为Hive可以使用MySQL作为元数据存储 2&#xff09;在安装Hive之前&#xff0c;需要先安装Hadoop。Hive是一个构建在Hadoop之上的数据仓库软件&#xff0c;它使用Hadoop的HDFS&#xff08;分布…

Crawl4AI:一个为大型语言模型(LLM)和AI应用设计的网页爬虫和数据提取工具实战

这里写目录标题 一、crawl4AI功能及简介1、简介2、特性 二、项目地址三、环境安装四、大模型申请五、代码示例1.生成markdown2.结构化数据 一、crawl4AI功能及简介 1、简介 Crawl4AI 是一个开源的网页爬虫和数据抓取工具&#xff0c;一个python项目&#xff0c;主要为大型语言…