现在这个代码编译有问题,帮我修正错误
/**************************************************************************************************/
/* 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 "fepPfm.h"
#include "common/applError.h"
#include <time.h>
#include <stdbool.h>
#include "cliLanDnsHandlers.h"
#include "dmlib/dmDnsProxyShell.h"
#include "uilib/uilibTpconfig.h"
#include "uilib/uilibTpconfigCpn.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>
/**************************************************************************************************/
/* DEFINES */
/**************************************************************************************************/
#define DNS_SERVER_MAX_RULES 120
#define DNS_DOMAIN_MAX_LENGTH 256
#define DNS_SERVER_MAX_LENGTH 256
#define DNS_NAME_MAX_LENGTH 64
#define IP_ADDRESS_MAX_LENGTH 46 // IPv6 max length
#define MAX_CLI_INPUT_LEN 256
#define MAX_ALIAS_COUNT 10
#define CLI_PRINT(pCliEnv, fmt, ...) cliPrintf((cli_env *)(pCliEnv), fmt, ##__VA_ARGS__)
#define DEFAULT_DNS_CONFIG_PATH "/etc/dnsproxy/dns_rules.conf"
STATUS create_default_rules(const char *path);
STATUS reset_to_default_rules(const char *path);
STATUS load_dns_rules(const char *path);
int mkdir_p(const char *path, mode_t mode);
const char *get_current_time_str(void);
// 改进 DEBUG_LOG 宏,添加 do-while 结构
#define DEBUG_LOG(fmt, ...) \
do { \
printf("[DEBUG] %s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); \
} while(0)
#define PRINT_FIELD(label, value) \
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, label, value ? value : "")
#define PRINT_FIELD_U(label, value) \
CLI_PRINT(pCliEnv, "%-*s: %u\n", FIELD_LABEL_WIDTH, label, value)
/**************************************************************************************************/
/* TYPES */
/**************************************************************************************************/
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;
bool modified;
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; // 添加加载状态标志
/**************************************************************************************************/
/* UTILITY FUNCTIONS */
/**************************************************************************************************/
void safe_strncpy(char *dest, const char *src, size_t dest_size) {
if (dest_size == 0) return;
strncpy(dest, src, dest_size - 1);
dest[dest_size - 1] = '\0';
}
// 链表节点计数
static int dlist_count(lanDns_node_t *head) {
int count = 0;
lanDns_node_t *current = head;
while (current) {
count++;
current = current->next;
}
return count;
}
void safe_strncat(char *dest, const char *src, size_t dest_size) {
if (dest_size == 0) return;
size_t dest_len = strlen(dest);
size_t src_len = strlen(src);
if (dest_len >= dest_size - 1) return; // 目标已满
size_t copy_len = src_len;
if (dest_len + src_len >= dest_size - 1) {
copy_len = dest_size - dest_len - 1;
}
strncat(dest, src, copy_len);
}
static const char* _rule_type_to_str(DNS_RULE_TYPE_E type) {
switch (type) {
case DNS_RULE_TYPE_IP: return "ip";
case DNS_RULE_TYPE_CNAME: return "cname";
case DNS_RULE_TYPE_FORWARD: return "forward";
default: return "ip";
}
}
// IP验证函数
bool is_valid_ip(const char *ip) {
struct sockaddr_in sa;
struct sockaddr_in6 sa6;
return (inet_pton(AF_INET, ip, &(sa.sin_addr)) != 0) ||
(inet_pton(AF_INET6, ip, &(sa6.sin6_addr)) != 0);
}
// CIDR格式验证
bool is_cidr_format(const char *cidr) {
if (!cidr || strlen(cidr) > 64) return false;
char copy[64];
strncpy(copy, cidr, sizeof(copy) - 1);
copy[sizeof(copy) - 1] = '\0';
char *slash = strchr(copy, '/');
if (!slash) return false;
*slash = '\0';
char *mask_str = slash + 1;
// 验证IP部分
struct in_addr addr;
if (inet_pton(AF_INET, copy, &addr) != 1) {
return false;
}
// 验证子网掩码部分
errno = 0;
char *end;
long mask = strtol(mask_str, &end, 10);
if (errno != 0 || *end != '\0' || mask < 0 || mask > 32) {
return false;
}
return true;
}
// 验证网络列表
static bool is_valid_network_list(const char *list) {
if (!list || strlen(list) == 0) return false;
char copy[256];
strncpy(copy, list, sizeof(copy) - 1);
copy[sizeof(copy) - 1] = '\0';
char *token = strtok(copy, ",");
while (token != NULL) {
// 跳过空格
while (*token == ' ') token++;
// 检查是否为"all"或CIDR格式
if (strcmp(token, "all") != 0 && !is_cidr_format(token)) {
return false;
}
token = strtok(NULL, ",");
}
return true;
}
STATUS reset_to_default_rules(const char *path) {
// 实际项目中这里应写入默认规则
// 简化版只返回成功
return create_default_rules(path);
}
STATUS ensure_dns_rules_loaded() {
// 1. 如果已加载则直接返回
if (g_dns_loaded) {
return OK;
}
// 2. 获取配置文件路径(支持环境变量覆盖)
const char *config_path = getenv("DNS_CONFIG_PATH");
if (!config_path) {
config_path = DEFAULT_DNS_CONFIG_PATH; // "/etc/appname/dns_rules.conf"
}
// 3. 检查文件是否存在
if (access(config_path, F_OK) != 0) {
// 3.1 文件不存在时自动创建
if (errno == ENOENT) {
if (create_default_rules(config_path) != OK) {
DEBUG_LOG("Failed to create config at %s: %s",
config_path, strerror(errno));
return ERROR;
}
} else {
// 3.2 权限或其他错误
DEBUG_LOG("Access error for %s: %s", config_path, strerror(errno));
return ERROR;
}
}
// 4. 检查文件是否为空
struct stat st;
if (stat(config_path, &st) == 0 && st.st_size == 0) {
// 4.1 空文件时重置为默认内容
if (reset_to_default_rules(config_path) != OK) {
DEBUG_LOG("Failed to reset empty config: %s", config_path);
return ERROR;
}
}
// 5. 加载规则
if (load_dns_rules(config_path) != OK) {
DEBUG_LOG("Failed to parse config: %s", config_path);
return ERROR;
}
g_dns_loaded = 1;
return OK;
}
STATUS create_default_rules(const char *path) {
// 1. 创建目录(如果不存在)
char dir_path[256] = {0};
strncpy(dir_path, path, sizeof(dir_path)-1);
char *last_slash = strrchr(dir_path, '/');
if (last_slash) {
*last_slash = '\0'; // 提取目录路径
if (mkdir_p(dir_path, 0755) != 0) { // 递归创建目录
DEBUG_LOG("Failed to create dir %s: %s", dir_path, strerror(errno));
return ERROR;
}
}
// 2. 创建并写入默认内容
FILE *fp = fopen(path, "w");
if (!fp) {
DEBUG_LOG("fopen failed: %s", 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;
}
int mkdir_p(const char *path, mode_t mode) {
char tmp[256];
char *p = NULL;
size_t len;
snprintf(tmp, sizeof(tmp), "%s", path);
len = strlen(tmp);
// 去除末尾斜杠
if (tmp[len - 1] == '/') {
tmp[len - 1] = 0;
}
// 逐级创建目录
for (p = tmp + 1; *p; p++) {
if (*p == '/') {
*p = 0;
if (mkdir(tmp, mode) != 0 && errno != EEXIST) {
return -1;
}
*p = '/';
}
}
// 创建最终目录
if (mkdir(tmp, mode) != 0 && errno != EEXIST) {
return -1;
}
return 0;
}
// 从链表删除节点
static void dlist_del(lanDns_node_t **head, lanDns_node_t *node) {
if (*head == NULL || node == NULL) return;
if (*head == node) {
*head = node->next;
} else {
lanDns_node_t *prev = *head;
while (prev->next != NULL && prev->next != node) {
prev = prev->next;
}
if (prev->next == node) {
prev->next = node->next;
}
}
free(node);
}
// 链表添加尾部节点
static void dlist_add_tail(lanDns_node_t **head, lanDns_node_t *new_node) {
if (!new_node) return;
if (*head == NULL) {
*head = new_node;
} else {
lanDns_node_t *current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = new_node;
}
new_node->next = NULL;
}
void destroy_landns_list() {
lanDns_node_t *curr = g_landns_list, *next;
while (curr) {
next = curr->next;
free(curr);
curr = next;
}
g_landns_list = NULL;
}
// 链表遍历宏
#define dlist_for_each_entry(pos, head) \
for (pos = head; pos != NULL; pos = pos->next)
// 安全遍历宏(支持删除)
#define dlist_for_each_entry_safe(pos, n, head) \
for (pos = head, n = (pos ? pos->next : NULL); \
pos != NULL; \
pos = n, n = (n ? n->next : NULL))
/**************************************************************************************************/
/* CORE FUNCTIONS */
/**************************************************************************************************/
// 查找节点辅助函数(使用数据库直接查询)
static lanDns_node_t* find_landns_node(const char *name) {
CFG_DNSSERVER_RULE_T *db_rule = NULL;
APPL_ERRCODE ret = dmDnsServerRuleGetByName(name, &db_rule);
if (ret != ERR_NO_ERROR || !db_rule) {
return NULL;
}
// 检查是否已在内存链表中
lanDns_node_t *node;
dlist_for_each_entry(node, g_landns_list) {
if (strcmp(node->rule.name, name) == 0) {
// 更新内存中的规则
memcpy(&node->rule, db_rule, sizeof(CFG_DNSSERVER_RULE_T));
DNSPROXYSHELL_FREE(db_rule);
return node;
}
}
// 创建新节点
node = malloc(sizeof(lanDns_node_t));
if (!node) {
DNSPROXYSHELL_FREE(db_rule);
return NULL;
}
memset(node, 0, sizeof(lanDns_node_t));
memcpy(&node->rule, db_rule, sizeof(CFG_DNSSERVER_RULE_T));
DNSPROXYSHELL_FREE(db_rule);
node->is_new = false;
node->modified = false;
node->next = NULL;
// 添加到链表
dlist_add_tail(&g_landns_list, node);
return node;
}
static lanDns_node_t* create_new_node(const char *name) {
lanDns_node_t *node = malloc(sizeof(lanDns_node_t));
if (!node) return NULL;
memset(node, 0, sizeof(lanDns_node_t));
safe_strncpy(node->rule.name, name, DNSPROXY_LEN_NAME32);
safe_strncpy(node->rule.status, "on", DNSPROXY_LEN_STATUS);
node->rule.ttl = 3600; // 默认TTL
// 初始化数组字段
memset(node->rule.aliases, 0, DNSPROXY_LEN_ALIASES);
memset(node->rule.ipv4_addrs, 0, DNSPROXY_LEN_IPV4_ADDRS);
memset(node->rule.ipv6_addrs, 0, DNSPROXY_LEN_IPV6_ADDRS);
memset(node->rule.dns_server, 0, DNSPROXY_LEN_DNS_SERVER);
memset(node->rule.cname, 0, DNSPROXY_LEN_CNAME);
safe_strncpy(node->rule.lan_networks, "all", DNSPROXY_LEN_LAN_NETWORKS);
node->is_new = true;
node->modified = true;
return node;
}
/**************************************************************************************************/
/* COMMAND HANDLERS */
/**************************************************************************************************/
// 1. Profile处理函数
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 || strlen(profileName) == 0) {
CLI_PRINT(pCliEnv, "%% Profile name cannot be empty\n");
return ERROR;
}
// 1. 先检查是否已在内存链表中(包括新创建的节点)
lanDns_node_t *node;
dlist_for_each_entry(node, g_landns_list) {
if (strcmp(node->rule.name, profileName) == 0) {
g_current_edit = node;
CLI_PRINT(pCliEnv, "%% Editing existing profile: %s\n", profileName);
return OK;
}
}
// 2. 尝试从数据库加载
g_current_edit = find_landns_node(profileName);
if (g_current_edit) {
CLI_PRINT(pCliEnv, "%% Editing profile: %s\n", profileName);
return OK;
}
// 3. 创建全新节点
g_current_edit = create_new_node(profileName);
if (!g_current_edit) {
CLI_PRINT(pCliEnv, "%% Failed to create profile '%s'\n", profileName);
return ERROR;
}
// 4. 添加新节点到内存链表(关键修复)
g_current_edit->next = g_landns_list;
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;
}
g_current_edit->modified = true;
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);
g_current_edit->modified = true;
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);
g_current_edit->modified = true;
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);
g_current_edit->modified = true;
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);
g_current_edit->modified = true;
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);
g_current_edit->modified = true;
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);
g_current_edit->modified = true;
CLI_PRINT(pCliEnv, "%% CNAME set to: %s\n", g_current_edit->rule.cname);
return OK;
}
// 9. DNS服务器处理函数
STATUS cli_lanDnsAddDnsServer(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;
}
char current_servers[DNSPROXY_LEN_DNS_SERVER];
strncpy(current_servers, g_current_edit->rule.dns_server, sizeof(current_servers));
// 检查服务器数量限制
int count = strlen(current_servers) > 0 ? 1 : 0;
for (char *p = current_servers; *p; p++) {
if (*p == ',') count++;
}
if (count >= 2) {
CLI_PRINT(pCliEnv, "%% Maximum DNS servers reached (2)\n");
return ERROR;
}
if (strlen(current_servers) > 0) {
strncat(current_servers, ",", sizeof(current_servers) - strlen(current_servers) - 1);
}
strncat(current_servers, dns_server, sizeof(current_servers) - strlen(current_servers) - 1);
safe_strncpy(g_current_edit->rule.dns_server, current_servers, DNSPROXY_LEN_DNS_SERVER);
g_current_edit->modified = true;
CLI_PRINT(pCliEnv, "%% DNS Server added: %s\n", dns_server);
return OK;
}
// 10. 处理属性删除
STATUS cli_lanDnsDeleteAttribute(cli_env *pCliEnv, char *attr) {
// 确保规则已加载
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_current_edit) {
CLI_PRINT(pCliEnv, "%% No active profile to modify\n");
return ERROR;
}
if (!attr) {
CLI_PRINT(pCliEnv, "%% Error: Attribute name must be specified\n");
return ERROR;
}
if (strcmp(attr, "alias") == 0) {
memset(g_current_edit->rule.aliases, 0, DNSPROXY_LEN_ALIASES);
g_current_edit->modified = true;
CLI_PRINT(pCliEnv, "%% Aliases cleared\n");
}
else if (strcmp(attr, "ipv4") == 0) {
memset(g_current_edit->rule.ipv4_addrs, 0, DNSPROXY_LEN_IPV4_ADDRS);
g_current_edit->modified = true;
CLI_PRINT(pCliEnv, "%% IPv4 addresses cleared\n");
}
else if (strcmp(attr, "ipv6") == 0) {
memset(g_current_edit->rule.ipv6_addrs, 0, DNSPROXY_LEN_IPV6_ADDRS);
g_current_edit->modified = true;
CLI_PRINT(pCliEnv, "%% IPv6 addresses cleared\n");
}
else if (strcmp(attr, "dns-server") == 0) {
memset(g_current_edit->rule.dns_server, 0, DNSPROXY_LEN_DNS_SERVER);
g_current_edit->modified = true;
CLI_PRINT(pCliEnv, "%% DNS servers cleared\n");
}
else if (strcmp(attr, "cname") == 0) {
memset(g_current_edit->rule.cname, 0, DNSPROXY_LEN_CNAME);
g_current_edit->modified = true;
CLI_PRINT(pCliEnv, "%% CNAME target cleared\n");
}
else {
CLI_PRINT(pCliEnv, "%% Error: Unsupported attribute '%s'\n", attr);
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;
}
// 验证网络格式
if (strcasecmp(networks, "all") != 0 && !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);
g_current_edit->modified = true;
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;
g_current_edit->modified = true;
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;
}
APPL_ERRCODE ret;
CFG_DNSSERVER_RULE_T *rule = &g_current_edit->rule;
// 如果是新规则,生成唯一ID
if (g_current_edit->is_new) {
time_t now = time(NULL);
snprintf(rule->id, DNSPROXY_LEN_ID, "dns_%ld_%03d", (long)now, rand() % 1000);
}
// 保存到数据库
if (g_current_edit->is_new) {
ret = dmDnsServerRuleAdd(rule);
} else {
ret = dmDnsServerRuleSet(rule);
}
if (ret == ERR_NO_ERROR) {
g_current_edit->is_new = false;
g_current_edit->modified = false;
CLI_PRINT(pCliEnv, "%% Changes committed successfully\n");
// 更新内存链表状态
if (!find_landns_node(rule->name)) {
// 确保规则在内存链表中
dlist_add_tail(&g_landns_list, g_current_edit);
}
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) {
CLI_PRINT(pCliEnv, "%% No active profile to show\n");
return ERROR;
}
static const int FIELD_LABEL_WIDTH = 24; // 使用足够大的宽度
CFG_DNSSERVER_RULE_T *rule = &g_current_edit->rule;
CLI_PRINT(pCliEnv, "LAN DNS Rule Configuration Summary:\n");
CLI_PRINT(pCliEnv, "----------------------------------------\n");
// 使用一致的格式化输出
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "Profile Name", rule->name);
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "Rule ID", rule->id ? rule->id : "N/A");
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "Status", rule->status);
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "Rule Type", rule->type);
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "Domain", rule->domain ? rule->domain : "N/A");
CLI_PRINT(pCliEnv, "%-*s: %u\n", FIELD_LABEL_WIDTH, "TTL", rule->ttl);
// 条件显示字段
if (rule->aliases && strlen(rule->aliases) > 0) {
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "Aliases", rule->aliases);
}
if (rule->lan_networks && strlen(rule->lan_networks) > 0) {
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "LAN Networks", rule->lan_networks);
}
if (rule->ipv4_addrs && strlen(rule->ipv4_addrs) > 0) {
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "IPv4 Addresses", rule->ipv4_addrs);
}
if (rule->ipv6_addrs && strlen(rule->ipv6_addrs) > 0) {
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "IPv6 Addresses", rule->ipv6_addrs);
}
if (rule->cname && strlen(rule->cname) > 0) {
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "CNAME Target", rule->cname);
}
if (rule->dns_server && strlen(rule->dns_server) > 0) {
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "DNS Servers", rule->dns_server);
}
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "Changes",
g_current_edit->modified ? "Modified (not committed)" : "No changes");
CLI_PRINT(pCliEnv, "%-*s: %s\n", FIELD_LABEL_WIDTH, "Record Status",
g_current_edit->is_new ? "New rule" : "Existing rule");
CLI_PRINT(pCliEnv, "----------------------------------------\n");
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 {
// 对于已存在的规则,丢弃修改
g_current_edit->modified = false;
// 恢复原始值(从数据库重新加载)
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);
}
// 18. 显示所有profile的函数
STATUS cli_lanDnsShowAll(cli_env *pCliEnv) {
// 确保规则已加载
if (ensure_dns_rules_loaded() != OK) {
return ERROR;
}
if (!g_landns_list) {
CLI_PRINT(pCliEnv, "%% No LAN DNS profiles configured\n");
return OK;
}
int count = dlist_count(g_landns_list);
CLI_PRINT(pCliEnv, "┌───────────────────────────────────────────────────────┐\n");
CLI_PRINT(pCliEnv, "│ Configured LAN DNS Profiles (%d) │\n", count);
CLI_PRINT(pCliEnv, "├──────────────┬──────────────┬──────────┬───────────────┤\n");
CLI_PRINT(pCliEnv, "│ Profile Name │ Status │ Type │ Domain │\n");
CLI_PRINT(pCliEnv, "├──────────────┼──────────────┼──────────┼───────────────┤\n");
lanDns_node_t *node;
dlist_for_each_entry(node, g_landns_list) {
CFG_DNSSERVER_RULE_T *rule = &node->rule;
// 截断过长的字符串
char name_display[14] = {0};
strncpy(name_display, rule->name, 12);
if (strlen(rule->name) > 12) strcat(name_display, "..");
char domain_display[15] = {0};
strncpy(domain_display, rule->domain, 13);
if (strlen(rule->domain) > 13) strcat(domain_display, "..");
CLI_PRINT(pCliEnv, "│ %-12s │ %-12s │ %-8s │ %-13s │\n",
name_display,
rule->status,
rule->type,
domain_display);
}
CLI_PRINT(pCliEnv, "└──────────────┴──────────────┴──────────┴───────────────┘\n");
return OK;
}
最新发布