这个LAN DNS CLI的程序哪里有非法指针的问题?应该是free的时候出现了非法指针
//
/* INCLUDE FILES */
//
#include “wm.h”
#include “wmb.h”
#include “rcc.h”
#include “cli_common.h”
#include “gml/data.h”
#include “dlist.h”
#include “midware/tpConfig.h”
#include “midware/tpState.h”
#include “common/applError.h”
#include <time.h>
#include <stdbool.h>
#include “cliLanDnsHandlers.h”
#include “dmlib/dmDnsProxyShell.h”
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libgen.h>
//
/* DEFINITIONS */
//
#define DNS_SERVER_MAX_RULES 120
#define DNS_DOMAIN_MAX_LENGTH 256
#define DNS_NAME_MAX_LENGTH 64
#define IP_ADDRESS_MAX_LENGTH 46
#define MAX_CLI_INPUT_LEN 256
#define MAX_ALIAS_COUNT 10
#define MAX_PATH_LEN 4096
#define FIXED_LABEL_WIDTH 18
#define DEFAULT_DNS_CONFIG_PATH “/etc/dnsproxy/dns_rules.conf”
#define MAX_DNS_SERVERS 2
#define MAX_INTERFACE_DESCRIPTIONS 4096
#define CLI_PRINT(pCliEnv, fmt, …) cliPrintf((cli_env *)(pCliEnv), fmt, ##VA_ARGS)
#ifdef DEBUG
#define DEBUG_LOG(fmt, …) printf("[DEBUG] %s:%d " fmt “\n”, func, LINE, ##VA_ARGS)
#else
#define DEBUG_LOG(fmt, …)
#endif
#define PRINT_FIELD(pCliEnv, label, value)
cliPrintf((cli_env *)(pCliEnv), “%-*s: %s\n”, FIXED_LABEL_WIDTH, label, value ? value : “”)
//
/* TYPE DEFINITIONS */
//
typedef enum {
DNS_RULE_TYPE_IP = 0,
DNS_RULE_TYPE_CNAME,
DNS_RULE_TYPE_FORWARD
} DNS_RULE_TYPE_E;
typedef struct lanDns_node {
CFG_DNSSERVER_RULE_T rule;
bool is_new;
struct lanDns_node *next;
} lanDns_node_t;
//
/* GLOBAL VARIABLES */
//
static lanDns_node_t *g_landns_list = NULL;
static lanDns_node_t *g_current_edit = NULL;
static bool g_dns_loaded = false;
// 存储所有接口描述信息
char g_interfaceDescriptions[MAX_INTERFACE_DESCRIPTIONS][NETIF_DESCRIPTION_LEN];
int g_interfaceCount = 0;
//
/* FUNCTION PROTOTYPES */
//
static STATUS create_default_rules(const char *path);
static STATUS reset_to_default_rules(const char *path);
static STATUS load_dns_rules(const char *path);
static int mkdir_p(const char *path, mode_t mode);
static const char *get_current_time_str(void);
static void safe_strncpy(char *dest, const char *src, size_t dest_size);
static bool is_valid_ip(const char *ip);
static bool is_cidr_format(const char *cidr);
static bool is_valid_network_list(const char *list);
static void dlist_add_tail(lanDns_node_t **head, lanDns_node_t *new_node);
static lanDns_node_t *find_landns_node(const char *name);
static lanDns_node_t *create_new_node(const char *name);
static void destroy_landns_list(void);
//
/* UTILITY FUNCTIONS */
//
void safe_strncpy(char *dest, const char *src, size_t dest_size) {
if (dest_size == 0) return;
if (src) {
strncpy(dest, src, dest_size - 1);
dest[dest_size - 1] = ‘\0’;
} else {
dest[0] = ‘\0’;
}
}
bool is_valid_ip(const char *ip) {
if (!ip) return false;
struct in_addr sa; struct in6_addr sa6; return (inet_pton(AF_INET, ip, &sa) == 1) || (inet_pton(AF_INET6, ip, &sa6) == 1);
}
bool is_cidr_format(const char *cidr) {
if (!cidr) return false;
char *slash = strchr(cidr, '/'); if (!slash) return false; char ip_str[IP_ADDRESS_MAX_LENGTH] = {0}; char mask_str[4] = {0}; size_t ip_len = slash - cidr; if (ip_len >= sizeof(ip_str)) return false; strncpy(ip_str, cidr, ip_len); strncpy(mask_str, slash + 1, sizeof(mask_str) - 1); char *end; long mask = strtol(mask_str, &end, 10); if (*end != '\0') return false; struct in_addr addr4; struct in6_addr addr6; if (inet_pton(AF_INET, ip_str, &addr4) == 1) { return mask >= 0 && mask <= 32; } if (inet_pton(AF_INET6, ip_str, &addr6) == 1) { return mask >= 0 && mask <= 128; } return false;
}
const char *get_current_time_str(void) {
static char buffer[64];
time_t now = time(NULL);
struct tm tm_info;
if (localtime_r(&now, &tm_info)) { strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm_info); } else { strcpy(buffer, "unknown"); } return buffer;
}
STATUS load_dns_rules(const char *path) {
return OK;
}
int mkdir_p(const char *path, mode_t mode) {
if (!path) return -1;
char tmp[MAX_PATH_LEN]; if (strlen(path) >= sizeof(tmp)) return -1; strcpy(tmp, path); char *p = tmp; if (*p == '/') p++; while (*p != '\0') { if (*p == '/') { *p = '\0'; if (mkdir(tmp, mode) != 0 && errno != EEXIST) { return -1; } *p = '/'; } p++; } return mkdir(tmp, mode);
}
STATUS reset_to_default_rules(const char *path) {
return create_default_rules(path);
}
STATUS create_default_rules(const char *path) {
if (!path) return ERROR;
// 创建配置文件目录 char dir_path[MAX_PATH_LEN]; strncpy(dir_path, path, sizeof(dir_path) - 1); dir_path[sizeof(dir_path) - 1] = '\0'; char *dir = dirname(dir_path); if (mkdir_p(dir, 0755) != 0) { DEBUG_LOG("Failed to create dir %s: %s", dir, strerror(errno)); return ERROR; } // 创建配置文件 FILE *fp = fopen(path, "w"); if (!fp) { DEBUG_LOG("Failed to create file %s: %s", path, strerror(errno)); return ERROR; } fprintf(fp, "# DNS Rules Configuration\n"); fprintf(fp, "# Version: 1.0\n"); fprintf(fp, "# Created: %s\n", get_current_time_str()); fprintf(fp, "\n[rules]\n\n"); fclose(fp); return OK;
}
STATUS ensure_dns_rules_loaded() {
if (g_dns_loaded) return OK;
const char *config_path = getenv("DNS_CONFIG_PATH") ?: DEFAULT_DNS_CONFIG_PATH; DEBUG_LOG("Using config path: %s", config_path); // 检查文件是否存在 if (access(config_path, F_OK) != 0) { if (errno == ENOENT) { DEBUG_LOG("Config file not found, creating: %s", config_path); if (create_default_rules(config_path) != OK) { DEBUG_LOG("Failed to create config: %s", strerror(errno)); return ERROR; } } else { DEBUG_LOG("Access error: %s", strerror(errno)); return ERROR; } } // 检查文件是否为空 struct stat st; if (stat(config_path, &st) != 0) { DEBUG_LOG("Failed to stat file: %s", strerror(errno)); return ERROR; } if (st.st_size == 0) { DEBUG_LOG("Config file is empty, resetting"); if (reset_to_default_rules(config_path) != OK) { DEBUG_LOG("Failed to reset config"); return ERROR; } } DEBUG_LOG("Loading rules from: %s", config_path); if (load_dns_rules(config_path) != OK) { DEBUG_LOG("Failed to parse config"); return ERROR; } g_dns_loaded = true; DEBUG_LOG("DNS rules loaded successfully"); return OK;
}
void dlist_add_tail(lanDns_node_t **head, lanDns_node_t *new_node) {
if (!new_node) return;
new_node->next = NULL;
if (*head == NULL) { *head = new_node; } else { lanDns_node_t *current = *head; while (current->next) { current = current->next; } current->next = new_node; }
}
lanDns_node_t *find_landns_node(const char *name) {
if (!name || !*name) return NULL;
CFG_DNSSERVER_RULE_T *db_rule = NULL; if (dmDnsServerRuleGetByName(name, &db_rule) != ERR_NO_ERROR) { return NULL; } // 检查内存列表中是否已有该规则 for (lanDns_node_t *node = g_landns_list; node; node = node->next) { if (strcmp(node->rule.name, name) == 0) { // 更新内存中的规则数据 memcpy(&node->rule, db_rule, sizeof(CFG_DNSSERVER_RULE_T)); DNSPROXYSHELL_FREE(db_rule); return node; } } // 创建新节点 lanDns_node_t *node = malloc(sizeof(lanDns_node_t)); if (!node) { DNSPROXYSHELL_FREE(db_rule); return NULL; } memset(node, 0, sizeof(*node)); memcpy(&node->rule, db_rule, sizeof(CFG_DNSSERVER_RULE_T)); DNSPROXYSHELL_FREE(db_rule); node->is_new = false; dlist_add_tail(&g_landns_list, node); return node;
}
lanDns_node_t *create_new_node(const char *name) {
if (!name || !*name) return NULL;
lanDns_node_t *node = malloc(sizeof(lanDns_node_t)); if (!node) return NULL; memset(node, 0, sizeof(*node)); safe_strncpy(node->rule.name, name, DNSPROXY_LEN_NAME32); safe_strncpy(node->rule.status, "on", DNSPROXY_LEN_STATUS); node->rule.ttl = 3600; safe_strncpy(node->rule.lan_networks, "all", DNSPROXY_LEN_LAN_NETWORKS); node->is_new = true; return node;
}
void destroy_landns_list() {
lanDns_node_t *curr = g_landns_list;
while (curr) {
lanDns_node_t *next = curr->next;
free(curr);
curr = next;
}
g_landns_list = NULL;
g_current_edit = NULL;
}
// 遍历回调函数 - 收集接口描述
GDSL_RET collectInterfaceDescriptions(TPSTATE_NETIF_ST *netIfEntry, void *param) {
if (g_interfaceCount >= MAX_INTERFACE_DESCRIPTIONS) {
return GDSL_RET_OK;
}
// 只收集非空描述 if (netIfEntry->description[0] != '\0') { strncpy(g_interfaceDescriptions[g_interfaceCount], netIfEntry->description, sizeof(g_interfaceDescriptions[0]) - 1); g_interfaceDescriptions[g_interfaceCount][sizeof(g_interfaceDescriptions[0]) - 1] = '\0'; g_interfaceCount++; } return GDSL_RET_OK;
}
// 初始化接口描述列表
void initInterfaceDescriptions() {
g_interfaceCount = 0;
uiNetIfStateTraversal(collectInterfaceDescriptions, NULL);
DEBUG_LOG(“Loaded %d interface descriptions”, g_interfaceCount);
}
// 检查输入是否匹配任何接口的描述
bool is_valid_interface_description(const char *description) {
if (!description || strlen(description) == 0) {
return false;
}
if (g_interfaceCount == 0) { initInterfaceDescriptions(); } for (int i = 0; i < g_interfaceCount; i++) { if (strcasecmp(description, g_interfaceDescriptions[i]) == 0) { return true; } } return false;
}
// 网络列表验证函数
bool is_valid_network_list(const char *list) {
if (!list) return false;
char *net_copy = strdup(list); if (!net_copy) return false; char *token = strtok(net_copy, ","); bool valid = true; while (token != NULL) { // 去除首尾空格 char *start = token; char *end = token + strlen(token) - 1; while (*start == ' ' && start < end) start++; while (*end == ' ' && end > start) end--; *(end + 1) = '\0'; // 检查有效的格式:"all"、CIDR或接口描述 if (strcmp(start, "all") != 0 && !is_cidr_format(start) && !is_valid_interface_description(start)) { valid = false; break; } token = strtok(NULL, ","); } free(net_copy); return valid;
}
//
/* COMMAND HANDLERS */
//
STATUS cli_lanDnsAddProfile(cli_env *pCliEnv, char *profileName) {
if (ensure_dns_rules_loaded() != OK) {
CLI_PRINT(pCliEnv, “%% Failed to load DNS rules\n”);
return ERROR;
}
if (!profileName || !*profileName) { CLI_PRINT(pCliEnv, "%% Profile name cannot be empty\n"); return ERROR; } // 检查是否已在编辑列表 for (lanDns_node_t *node = g_landns_list; node; node = node->next) { if (strcmp(node->rule.name, profileName) == 0) { g_current_edit = node; CLI_PRINT(pCliEnv, "%% Editing profile: %s\n", profileName); return OK; } } // 尝试从数据库加载 g_current_edit = find_landns_node(profileName); if (g_current_edit) { CLI_PRINT(pCliEnv, "%% Editing profile: %s\n", profileName); return OK; } // 创建新节点 g_current_edit = create_new_node(profileName); if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% Failed to create profile\n"); return ERROR; } initInterfaceDescriptions(); dlist_add_tail(&g_landns_list, g_current_edit); CLI_PRINT(pCliEnv, "%% Created new profile: %s\n", profileName); return OK;
}
// 2. 处理类型设置
STATUS cli_lanDnsAddType(cli_env *pCliEnv, char *typeName) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (strcasecmp(typeName, "ip") == 0) { safe_strncpy(g_current_edit->rule.type, "ip", DNSPROXY_LEN_TYPE); } else if (strcasecmp(typeName, "cname") == 0) { safe_strncpy(g_current_edit->rule.type, "cname", DNSPROXY_LEN_TYPE); } else if (strcasecmp(typeName, "forward") == 0) { safe_strncpy(g_current_edit->rule.type, "forward", DNSPROXY_LEN_TYPE); } else { CLI_PRINT(pCliEnv, "%% Invalid type. Use ip/cname/forward\n"); return ERROR; } CLI_PRINT(pCliEnv, "%% Rule type set to: %s\n", g_current_edit->rule.type); return OK;
}
// 3. 域名处理函数
STATUS cli_lanDnsAddDomain(cli_env *pCliEnv, char *domain) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (!domain || strlen(domain) == 0) { CLI_PRINT(pCliEnv, "%% Error: Domain cannot be empty\n"); return ERROR; } // 域名长度检查 if (strlen(domain) >= DNSPROXY_LEN_DOMAIN) { CLI_PRINT(pCliEnv, "%% Domain too long (max %d chars)\n", DNSPROXY_LEN_DOMAIN - 1); return ERROR; } safe_strncpy(g_current_edit->rule.domain, domain, DNSPROXY_LEN_DOMAIN); CLI_PRINT(pCliEnv, "%% Domain set to: %s\n", g_current_edit->rule.domain); return OK;
}
// 4. 别名处理函数
STATUS cli_lanDnsAddAlias(cli_env *pCliEnv, char *alias) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (!alias || strlen(alias) == 0) { CLI_PRINT(pCliEnv, "%% Error: Alias cannot be empty\n"); return ERROR; } // 别名长度检查 if (strlen(alias) >= DNSPROXY_LEN_DOMAIN) { CLI_PRINT(pCliEnv, "%% Alias too long (max %d chars)\n", DNSPROXY_LEN_DOMAIN - 1); return ERROR; } char current_aliases[DNSPROXY_LEN_ALIASES]; strncpy(current_aliases, g_current_edit->rule.aliases, sizeof(current_aliases)); if (strlen(current_aliases) > 0) { // 检查别名数量限制 int count = 1; for (char *p = current_aliases; *p; p++) { if (*p == ',') count++; } if (count >= MAX_ALIAS_COUNT) { CLI_PRINT(pCliEnv, "%% Maximum aliases reached (%d)\n", MAX_ALIAS_COUNT); return ERROR; } strncat(current_aliases, ",", sizeof(current_aliases) - strlen(current_aliases) - 1); } strncat(current_aliases, alias, sizeof(current_aliases) - strlen(current_aliases) - 1); safe_strncpy(g_current_edit->rule.aliases, current_aliases, DNSPROXY_LEN_ALIASES); CLI_PRINT(pCliEnv, "%% Alias added: %s\n", alias); return OK;
}
// 5. 状态处理函数
STATUS cli_lanDnsAddStatus(cli_env *pCliEnv, char *status) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (strcasecmp(status, "on") == 0 || strcasecmp(status, "off") == 0) { safe_strncpy(g_current_edit->rule.status, status, DNSPROXY_LEN_STATUS); CLI_PRINT(pCliEnv, "%% Status set to: %s\n", g_current_edit->rule.status); return OK; } CLI_PRINT(pCliEnv, "%% Invalid status. Use on/off\n"); return ERROR;
}
// 6. IPv4处理函数
STATUS cli_lanDnsAddIpv4(cli_env *pCliEnv, char *ip) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (!ip || !is_valid_ip(ip)) { CLI_PRINT(pCliEnv, "%% Invalid IPv4 address\n"); return ERROR; } // 检查是否是有效的IPv4地址 (AF_INET) struct sockaddr_in sa; if (inet_pton(AF_INET, ip, &(sa.sin_addr)) == 0) { CLI_PRINT(pCliEnv, "%% Not a valid IPv4 address\n"); return ERROR; } safe_strncpy(g_current_edit->rule.ipv4_addrs, ip, DNSPROXY_LEN_IPV4_ADDRS); CLI_PRINT(pCliEnv, "%% IPv4 set to: %s\n", g_current_edit->rule.ipv4_addrs); return OK;
}
// 7. IPv6处理函数
STATUS cli_lanDnsAddIpv6(cli_env *pCliEnv, char *ip) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (!ip || !is_valid_ip(ip)) { CLI_PRINT(pCliEnv, "%% Invalid IPv6 address\n"); return ERROR; } // 检查是否是有效的IPv6地址 (AF_INET6) struct sockaddr_in6 sa6; if (inet_pton(AF_INET6, ip, &(sa6.sin6_addr)) == 0) { CLI_PRINT(pCliEnv, "%% Not a valid IPv6 address\n"); return ERROR; } safe_strncpy(g_current_edit->rule.ipv6_addrs, ip, DNSPROXY_LEN_IPV6_ADDRS); CLI_PRINT(pCliEnv, "%% IPv6 set to: %s\n", g_current_edit->rule.ipv6_addrs); return OK;
}
// 8. CNAME处理函数
STATUS cli_lanDnsAddCname(cli_env *pCliEnv, char *cname) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (!cname || strlen(cname) == 0) { CLI_PRINT(pCliEnv, "%% Error: CNAME cannot be empty\n"); return ERROR; } // CNAME长度检查 if (strlen(cname) >= DNSPROXY_LEN_CNAME) { CLI_PRINT(pCliEnv, "%% CNAME too long (max %d chars)\n", DNSPROXY_LEN_CNAME - 1); return ERROR; } safe_strncpy(g_current_edit->rule.cname, cname, DNSPROXY_LEN_CNAME); CLI_PRINT(pCliEnv, "%% CNAME set to: %s\n", g_current_edit->rule.cname); return OK;
}
// 9. DNS服务器处理函数
STATUS cli_lanDnsAddDnsServer1(cli_env *pCliEnv, char *dns_server) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (!dns_server || !is_valid_ip(dns_server)) { CLI_PRINT(pCliEnv, "%% Invalid DNS server address\n"); return ERROR; } // 验证是否为有效IP地址 struct sockaddr_in sa; if (inet_pton(AF_INET, dns_server, &(sa.sin_addr)) == 0) { CLI_PRINT(pCliEnv, "%% Not a valid IPv4 address\n"); return ERROR; } safe_strncpy(g_current_edit->rule.dns_server1, dns_server, DNSPROXY_LEN_SERVER_IP); CLI_PRINT(pCliEnv, "%% Primary DNS server set to: %s\n", g_current_edit->rule.dns_server1); return OK;
}
STATUS cli_lanDnsAddDnsServer2(cli_env *pCliEnv, char *dns_server) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (!dns_server || !is_valid_ip(dns_server)) { CLI_PRINT(pCliEnv, "%% Invalid DNS server address\n"); return ERROR; } // 验证是否为有效IP地址 struct sockaddr_in sa; if (inet_pton(AF_INET, dns_server, &(sa.sin_addr)) == 0) { CLI_PRINT(pCliEnv, "%% Not a valid IPv4 address\n"); return ERROR; } safe_strncpy(g_current_edit->rule.dns_server2, dns_server, DNSPROXY_LEN_SERVER_IP); CLI_PRINT(pCliEnv, "%% Secondary DNS server set to: %s\n", g_current_edit->rule.dns_server2); return OK;
}
// 10. 处理属性删除
STATUS cli_lanDnsDeleteAttribute(cli_env *pCliEnv, char *attr) {
// 1. 前置检查和验证
if (ensure_dns_rules_loaded() != OK) {
RCC_EXT_WriteStrLine(pCliEnv, “%% Error: Failed to load DNS rules”);
return ERROR;
}
if (!g_current_edit) { RCC_EXT_WriteStrLine(pCliEnv, "%% Error: No active profile to modify. " "Use 'profile <name>' first"); return ERROR; } if (!attr || *attr == '\0') { RCC_EXT_WriteStrLine(pCliEnv, "%% Error: Attribute name must be specified\n" "Valid attributes: alias, ipv4, ipv6, dnsserver, " "cname, domain, lannetworks, status, ttl, type"); return ERROR; } // 2. 获取当前编辑规则指针 CFG_DNSSERVER_RULE_T *rule = &g_current_edit->rule; // 3. 扩展的属性处理逻辑 if (strcasecmp(attr, "alias") == 0 || strcasecmp(attr, "aliases") == 0) { memset(rule->aliases, 0, DNSPROXY_LEN_ALIASES); RCC_EXT_WriteStrLine(pCliEnv, "%% Aliases cleared"); } else if (strcasecmp(attr, "ipv4") == 0) { memset(rule->ipv4_addrs, 0, DNSPROXY_LEN_IPV4_ADDRS); RCC_EXT_WriteStrLine(pCliEnv, "%% IPv4 addresses cleared"); } else if (strcasecmp(attr, "ipv6") == 0) { memset(rule->ipv6_addrs, 0, DNSPROXY_LEN_IPV6_ADDRS); RCC_EXT_WriteStrLine(pCliEnv, "%% IPv6 addresses cleared"); } else if (strcasecmp(attr, "dnsserver1") == 0) { memset(rule->dns_server1, 0, DNSPROXY_LEN_DNS_SERVER); RCC_EXT_WriteStrLine(pCliEnv, "%% Primary DNS server cleared"); } else if (strcasecmp(attr, "dnsserver2") == 0) { memset(rule->dns_server2, 0, DNSPROXY_LEN_DNS_SERVER); RCC_EXT_WriteStrLine(pCliEnv, "%% Secondary DNS server cleared"); } else if (strcasecmp(attr, "cname") == 0) { memset(rule->cname, 0, DNSPROXY_LEN_CNAME); RCC_EXT_WriteStrLine(pCliEnv, "%% CNAME target cleared"); } // === 新增支持的可删除属性 === else if (strcasecmp(attr, "domain") == 0) { memset(rule->domain, 0, DNSPROXY_LEN_DOMAIN); RCC_EXT_WriteStrLine(pCliEnv, "%% Domain cleared"); } else if (strcasecmp(attr, "lannetworks") == 0) { memset(rule->lan_networks, 0, DNSPROXY_LEN_LAN_NETWORKS); RCC_EXT_WriteStrLine(pCliEnv, "%% LAN networks cleared"); } else if (strcasecmp(attr, "status") == 0) { // 重置为默认状态 (假设默认是"off") snprintf(rule->status, DNSPROXY_LEN_STATUS, "off"); RCC_EXT_WriteStrLine(pCliEnv, "%% Status reset to default (off)"); } else if (strcasecmp(attr, "type") == 0) { // 类型清空(必须重新设置才能提交) memset(rule->type, 0, DNSPROXY_LEN_TYPE); RCC_EXT_WriteStrLine(pCliEnv, "%% Type cleared. Warning: Type must be set before commit!"); } else if (strcasecmp(attr, "ttl") == 0) { // TTL重置为默认值0 rule->ttl = 0; RCC_EXT_WriteStrLine(pCliEnv, "%% TTL reset to default (0)"); } else { // 4. 无效属性处理 char errorMsg[128]; snprintf(errorMsg, sizeof(errorMsg), "%% Error: Unsupported attribute '%s'\n" "Valid attributes: alias, ipv4, ipv6, dnsserver, cname, " "domain, lannetworks, status, ttl, type", attr); RCC_EXT_WriteStrLine(pCliEnv, errorMsg); return ERROR; } return OK;
}
// 11. LAN网络设置函数
STATUS cli_lanDnsAddLanNetworks(cli_env *pCliEnv, char *networks) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (!networks || strlen(networks) == 0) { CLI_PRINT(pCliEnv, "%% Error: LAN networks cannot be empty\n"); return ERROR; } // 初始化接口描述列表 initInterfaceDescriptions(); // 验证网络格式 if (!is_valid_network_list(networks)) { CLI_PRINT(pCliEnv, "%% Invalid LAN networks format.\n"); return ERROR; } // 复制并存储值 safe_strncpy(g_current_edit->rule.lan_networks, networks, DNSPROXY_LEN_LAN_NETWORKS); CLI_PRINT(pCliEnv, "%% LAN networks set to: %s\n", g_current_edit->rule.lan_networks); return OK;
}
// 12. TTL设置函数
STATUS cli_lanDnsAddTtl(cli_env *pCliEnv, char *ttl_str) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile. Use 'profile <name>' first\n"); return ERROR; } if (!ttl_str || strlen(ttl_str) == 0) { CLI_PRINT(pCliEnv, "%% Error: TTL cannot be empty\n"); return ERROR; } char *endptr; long ttl = strtol(ttl_str, &endptr, 10); if (*endptr != '\0' || ttl <= 0 || ttl > 86400) { // 限制在1秒到1天之间 CLI_PRINT(pCliEnv, "%% Invalid TTL. Must be integer between 1 and 86400\n"); return ERROR; } g_current_edit->rule.ttl = (uint32_t)ttl; CLI_PRINT(pCliEnv, "%% TTL set to: %u\n", g_current_edit->rule.ttl); return OK;
}
// 13. 提交更改到数据库
STATUS cli_lanDnsCommit(cli_env *pCliEnv) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile to commit\n"); return ERROR; } // 验证规则完整性 if (!g_current_edit->rule.name[0] || !g_current_edit->rule.domain[0] || !g_current_edit->rule.type[0]) { CLI_PRINT(pCliEnv, "%% Incomplete rule: name, domain and type are required\n"); return ERROR; } if (strcmp(g_current_edit->rule.type, "forward") == 0) { if (g_current_edit->rule.dns_server1[0] == '\0' && g_current_edit->rule.dns_server2[0] == '\0') { CLI_PRINT(pCliEnv, "%% At least one DNS server is required for forward rules\n"); return ERROR; } } APPL_ERRCODE ret = ERR_NO_ERROR; CFG_DNSSERVER_RULE_T *rule = &g_current_edit->rule; if (g_current_edit->is_new) { memset(rule->id, 0, DNSPROXY_LEN_ID); } // 保存到数据库 if (g_current_edit->is_new) { ret = dmDnsServerRuleAdd(rule); } else { ret = dmDnsServerRuleSet(rule); } if (ret == ERR_NO_ERROR) { g_current_edit->is_new = false; CLI_PRINT(pCliEnv, "%% Changes committed successfully\n"); // 更新规则ID(如果是新添加的规则) if (g_current_edit->is_new == false && rule->id[0] == '\0') { // 特殊处理:如果数据库未设置ID,获取最新规则 CFG_DNSSERVER_RULE_T *db_rule = NULL; if (dmDnsServerRuleGetByName(rule->name, &db_rule) == ERR_NO_ERROR) { strncpy(rule->id, db_rule->id, DNSPROXY_LEN_ID); DNSPROXYSHELL_FREE(db_rule); } } return OK; } else { CLI_PRINT(pCliEnv, "%% Error committing changes (code: 0x%X)\n", ret); return ERROR; }
}
// 14. 显示当前配置
STATUS cli_lanDnsShow(cli_env *pCliEnv) {
if (!g_current_edit) {
RCC_EXT_WriteStrLine(pCliEnv, “%% No active profile to show”);
return ERROR;
}
CFG_DNSSERVER_RULE_T *rule = &g_current_edit->rule; char buffer[256] = {0}; // 标题行 RCC_EXT_WriteStrLine(pCliEnv, "LAN DNS Rule Configuration Summary:"); RCC_EXT_WriteStrLine(pCliEnv, "----------------------------------------"); // 核心字段(使用安全的snprintf) snprintf(buffer, sizeof(buffer), "Profile Name: %s", rule->name); RCC_EXT_WriteStrLine(pCliEnv, buffer); if (rule->id[0]) { snprintf(buffer, sizeof(buffer), "Rule ID: %s", rule->id); RCC_EXT_WriteStrLine(pCliEnv, buffer); } snprintf(buffer, sizeof(buffer), "Status: %s", rule->status); RCC_EXT_WriteStrLine(pCliEnv, buffer); snprintf(buffer, sizeof(buffer), "Rule Type: %s", rule->type); RCC_EXT_WriteStrLine(pCliEnv, buffer); snprintf(buffer, sizeof(buffer), "Domain: %s", rule->domain); RCC_EXT_WriteStrLine(pCliEnv, buffer); // 条件输出字段 if (rule->aliases[0]) { snprintf(buffer, sizeof(buffer), "Aliases: %s", rule->aliases); RCC_EXT_WriteStrLine(pCliEnv, buffer); } snprintf(buffer, sizeof(buffer), "TTL: %u", rule->ttl); RCC_EXT_WriteStrLine(pCliEnv, buffer); snprintf(buffer, sizeof(buffer), "LAN Networks: %s", rule->lan_networks); RCC_EXT_WriteStrLine(pCliEnv, buffer); if (rule->ipv4_addrs[0]) { snprintf(buffer, sizeof(buffer), "IPv4 Addresses: %s", rule->ipv4_addrs); RCC_EXT_WriteStrLine(pCliEnv, buffer); } if (rule->ipv6_addrs[0]) { snprintf(buffer, sizeof(buffer), "IPv6 Addresses: %s", rule->ipv6_addrs); RCC_EXT_WriteStrLine(pCliEnv, buffer); } if (rule->cname[0]) { snprintf(buffer, sizeof(buffer), "CNAME Target: %s", rule->cname); RCC_EXT_WriteStrLine(pCliEnv, buffer); } if (rule->dns_server1[0] || rule->dns_server2[0]) { snprintf(buffer, sizeof(buffer), "Primary DNS: %s", rule->dns_server1[0] ? rule->dns_server1 : "Not set"); RCC_EXT_WriteStrLine(pCliEnv, buffer); snprintf(buffer, sizeof(buffer), "Secondary DNS: %s", rule->dns_server2[0] ? rule->dns_server2 : "Not set"); RCC_EXT_WriteStrLine(pCliEnv, buffer); } snprintf(buffer, sizeof(buffer), "Record Status: %s", g_current_edit->is_new ? "New rule" : "Existing rule"); RCC_EXT_WriteStrLine(pCliEnv, buffer); RCC_EXT_WriteStrLine(pCliEnv, "----------------------------------------"); return OK;
}
/****************************************************************************************/
// 15. 退出配置模式函数
STATUS cli_lanDnsCancel(cli_env *pCliEnv) {
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) { CLI_PRINT(pCliEnv, "%% No active profile to cancel\n"); return ERROR; } char profile_name[DNSPROXY_LEN_NAME32]; strncpy(profile_name, g_current_edit->rule.name, sizeof(profile_name)); // 如果是新建但未提交的规则,直接删除 if (g_current_edit->is_new) { // 从内存链表删除 lanDns_node_t *prev = NULL; lanDns_node_t *curr = g_landns_list; while (curr && curr != g_current_edit) { prev = curr; curr = curr->next; } if (curr == g_current_edit) { if (prev) prev->next = g_current_edit->next; else g_landns_list = g_current_edit->next; } // 释放节点内存 free(g_current_edit); } else { // 恢复原始值(从数据库重新加载) CFG_DNSSERVER_RULE_T *db_rule = NULL; APPL_ERRCODE ret = dmDnsServerRuleGetByName(profile_name, &db_rule); if (ret == ERR_NO_ERROR && db_rule) { memcpy(&g_current_edit->rule, db_rule, sizeof(CFG_DNSSERVER_RULE_T)); DNSPROXYSHELL_FREE(db_rule); } } g_current_edit = NULL; CLI_PRINT(pCliEnv, "%% Cancelled editing for profile: %s\n", profile_name); return OK;
}
// 16. 退出配置模式函数(不带参数)
STATUS cli_lanDnsExit(cli_env *pCliEnv) {
return cli_lanDnsCancel(pCliEnv);
}
//删除指定landns
STATUS cli_lanDnsDeleteProfile(cli_env *pCliEnv, char *profileName) {
if (!pCliEnv || !profileName || *profileName == ‘\0’) {
RCC_EXT_WriteStrLine(pCliEnv, “%% Error: Invalid parameters”);
return ERROR;
}
if (ensure_dns_rules_loaded() != OK) { RCC_EXT_WriteStrLine(pCliEnv, "%% Error: Failed to load DNS rules"); return ERROR; } // 查找数据库中的规则 CFG_DNSSERVER_RULE_T *db_rule = NULL; APPL_ERRCODE ret = dmDnsServerRuleGetByName(profileName, &db_rule); if (ret != ERR_NO_ERROR || !db_rule) { RCC_EXT_WriteStrLine(pCliEnv, "%% Error: Profile not found"); return ERROR; } // 获取规则ID unsigned id = 0; if (db_rule->id[0]) { id = (unsigned)atoi(db_rule->id); } if (id == 0) { RCC_EXT_WriteStrLine(pCliEnv, "%% Error: Invalid profile ID"); DNSPROXYSHELL_FREE(db_rule); return ERROR; } // 删除数据库中的规则 ret = dmDnsServerRuleDelById(id); DNSPROXYSHELL_FREE(db_rule); if (ret != ERR_NO_ERROR) { char errMsg[64]; snprintf(errMsg, sizeof(errMsg), "%% Error: Delete failed (0x%X)", ret); RCC_EXT_WriteStrLine(pCliEnv, errMsg); return ERROR; } //更新内存链表 lanDns_node_t *prev = NULL; lanDns_node_t *curr = g_landns_list; while (curr) { if (strcmp(curr->rule.name, profileName) == 0) { //如果当前编辑的是要删除的节点,重置编辑状态 if (g_current_edit == curr) { g_current_edit = NULL; } // 从链表中删除节点 if (prev) { prev->next = curr->next; } else { g_landns_list = curr->next; } free(curr); break; } prev = curr; curr = curr->next; } char successMsg[128]; snprintf(successMsg, sizeof(successMsg), "%% Deleted profile '%s' (ID: %u)", profileName, id); RCC_EXT_WriteStrLine(pCliEnv, successMsg); return OK;
}
STATUS cli_lanDnsShowAll(cli_env *pCliEnv) {
APPL_ERRCODE ret = ERR_NO_ERROR;
// 1. 从数据库获取所有规则 CFG_DNSSERVER_RULE_T **rules = NULL; ret = dmDnsServerRuleGetAll(&rules); if (ret != ERR_NO_ERROR) { char errMsg[128]; snprintf(errMsg, sizeof(errMsg), "%% Error: Failed to get DNS rules (code: 0x%X)", ret); CLI_PRINT(pCliEnv, errMsg); return ERROR; } // 2. 检查规则数量 int ruleCount = 0; if (rules != NULL) { while (rules[ruleCount] != NULL) { ruleCount++; } } if (ruleCount == 0) { CLI_PRINT(pCliEnv, "%% No LAN DNS rules found in database"); dmDnsServerRuleListFree(rules); return OK; } // 3. 打印总览标题 CLI_PRINT(pCliEnv, "LAN DNS Rules Configuration (%d rules total)\n", ruleCount); CLI_PRINT(pCliEnv, "----------------------------------------\n"); // 4. 遍历并单独打印每个规则 for (int i = 0; i < ruleCount; i++) { CFG_DNSSERVER_RULE_T *rule = rules[i]; char buffer[256]; // 规则标题 snprintf(buffer, sizeof(buffer), "%d. LAN DNS: %s\n", i + 1, rule->name); CLI_PRINT(pCliEnv, buffer); // 核心字段 snprintf(buffer, sizeof(buffer), "Profile Name: %s\n", rule->name); CLI_PRINT(pCliEnv, buffer); if (rule->id[0]) { snprintf(buffer, sizeof(buffer), "Rule ID: %s\n", rule->id); CLI_PRINT(pCliEnv, buffer); } snprintf(buffer, sizeof(buffer), "Status: %s\n", rule->status); CLI_PRINT(pCliEnv, buffer); snprintf(buffer, sizeof(buffer), "Rule Type: %s\n", rule->type); CLI_PRINT(pCliEnv, buffer); snprintf(buffer, sizeof(buffer), "Domain: %s\n", rule->domain); CLI_PRINT(pCliEnv, buffer); if (rule->aliases[0]) { snprintf(buffer, sizeof(buffer), "Aliases: %s\n", rule->aliases); CLI_PRINT(pCliEnv, buffer); } snprintf(buffer, sizeof(buffer), "TTL: %u\n", rule->ttl); CLI_PRINT(pCliEnv, buffer); snprintf(buffer, sizeof(buffer), "LAN Networks: %s\n", rule->lan_networks); CLI_PRINT(pCliEnv, buffer); // 类型相关字段 if (strcmp(rule->type, "ip") == 0) { if (rule->ipv4_addrs[0]) { snprintf(buffer, sizeof(buffer), "IPv4 Addresses: %s\n", rule->ipv4_addrs); CLI_PRINT(pCliEnv, buffer); } if (rule->ipv6_addrs[0]) { snprintf(buffer, sizeof(buffer), "IPv6 Addresses: %s\n", rule->ipv6_addrs); CLI_PRINT(pCliEnv, buffer); } } else if (strcmp(rule->type, "cname") == 0) { if (rule->cname[0]) { snprintf(buffer, sizeof(buffer), "CNAME Target: %s\n", rule->cname); CLI_PRINT(pCliEnv, buffer); } } else if (strcmp(rule->type, "forward") == 0) { if (rule->dns_server[0]) { snprintf(buffer, sizeof(buffer), "DNS Servers: %s\n", rule->dns_server); CLI_PRINT(pCliEnv, buffer); } } // 规则间分隔线 if (i < ruleCount - 1) { CLI_PRINT(pCliEnv, "----------------------------------------\n"); } } // 5. 打印结束分隔线 CLI_PRINT(pCliEnv, "----------------------------------------\n"); // 6. 释放内存 dmDnsServerRuleListFree(rules); return OK;
}
//
/* UPDATED DETAILED VIEW COMMAND */
//
STATUS cli_lanDnsShowDetail(cli_env *pCliEnv, char *profileName) {
if (!profileName || *profileName == ‘\0’) {
CLI_PRINT(pCliEnv, “%% Error: Profile name required”);
return ERROR;
}
APPL_ERRCODE ret = ERR_NO_ERROR; CFG_DNSSERVER_RULE_T *rule = NULL; // 1. 从数据库获取指定规则 ret = dmDnsServerRuleGetByName(profileName, &rule); if (ret != ERR_NO_ERROR || rule == NULL) { CLI_PRINT(pCliEnv, "%% Error: Profile '%s' not found", profileName); return ERROR; } char buffer[256]; // 2. 打印详细标题 snprintf(buffer, sizeof(buffer), "LAN DNS Rule: %s\n", profileName); CLI_PRINT(pCliEnv, buffer); CLI_PRINT(pCliEnv, "----------------------------------------\n"); // 3. 打印基本信息 snprintf(buffer, sizeof(buffer), "Profile Name: %s\n", rule->name); CLI_PRINT(pCliEnv, buffer); if (rule->id[0]) { snprintf(buffer, sizeof(buffer), "Rule ID: %s\n", rule->id); CLI_PRINT(pCliEnv, buffer); } snprintf(buffer, sizeof(buffer), "Status: %s\n", rule->status); CLI_PRINT(pCliEnv, buffer); snprintf(buffer, sizeof(buffer), "Rule Type: %s\n", rule->type); CLI_PRINT(pCliEnv, buffer); snprintf(buffer, sizeof(buffer), "Domain: %s\n", rule->domain); CLI_PRINT(pCliEnv, buffer); if (rule->aliases[0]) { snprintf(buffer, sizeof(buffer), "Aliases: %s\n", rule->aliases); CLI_PRINT(pCliEnv, buffer); } snprintf(buffer, sizeof(buffer), "TTL: %u\n", rule->ttl); CLI_PRINT(pCliEnv, buffer); snprintf(buffer, sizeof(buffer), "LAN Networks: %s\n", rule->lan_networks); CLI_PRINT(pCliEnv, buffer); // 4. 打印类型相关字段 if (strcmp(rule->type, "ip") == 0) { if (rule->ipv4_addrs[0]) { snprintf(buffer, sizeof(buffer), "IPv4 Addresses: %s\n", rule->ipv4_addrs); CLI_PRINT(pCliEnv, buffer); } if (rule->ipv6_addrs[0]) { snprintf(buffer, sizeof(buffer), "IPv6 Addresses: %s\n", rule->ipv6_addrs); CLI_PRINT(pCliEnv, buffer); } } else if (strcmp(rule->type, "cname") == 0) { if (rule->cname[0]) { snprintf(buffer, sizeof(buffer), "CNAME Target: %s\n", rule->cname); CLI_PRINT(pCliEnv, buffer); } } else if (strcmp(rule->type, "forward") == 0) { if (rule->dns_server1[0]) { snprintf(buffer, sizeof(buffer), "Primary DNS Server: %s", rule->dns_server1); } else { snprintf(buffer, sizeof(buffer), "Primary DNS Server: Not set"); } CLI_PRINT(pCliEnv, buffer); if (rule->dns_server2[0]) { snprintf(buffer, sizeof(buffer), "Secondary DNS Server: %s", rule->dns_server2); } else { snprintf(buffer, sizeof(buffer), "Secondary DNS Server: Not set"); } CLI_PRINT(pCliEnv, buffer); } // 5. 打印分隔线结尾 CLI_PRINT(pCliEnv, "----------------------------------------\n"); // 6. 释放内存 DNSPROXYSHELL_FREE(rule); return OK;
}