1390 lines
40 KiB
C
1390 lines
40 KiB
C
//
|
||
// config.c
|
||
//
|
||
// Created by sunguosong on 2019/8/13.
|
||
//
|
||
|
||
#include "config.h"
|
||
|
||
/*==============================================================================*
|
||
* TEST-DATA |
|
||
*==============================================================================*/
|
||
|
||
// 测试数据iptables-save 配置文件路径
|
||
static const char *__iptables_conf_dir = "./iptables-conf.txt";
|
||
// 测试数据json
|
||
static const char *__json = "{ \"config_type\":3, \"content\":[ \
|
||
{\"action\":1,\"i_device\":\"ens33\",\"source\":\"192.168.12.12\",\
|
||
\"target\":\"SNAT\",\"to\":\"172.18.2.72\"}, \
|
||
{ \
|
||
\"action\": 1,\
|
||
\"target\": \"SNAT\", \
|
||
\"prot\": \"udp\", \
|
||
\"source\": \"192.168.80.0/24\", \
|
||
\"destination\": \"\", \
|
||
\"dport\": \"\", \
|
||
\"to\": \"10.10.10.1:450700-45100\", \
|
||
\"i_device\": \"\", \
|
||
\"o_device\": \"ens33\", \
|
||
\"match\": \"\", \
|
||
\"match_info\": \"\" \
|
||
}, \
|
||
{ \
|
||
\"action\": 1,\
|
||
\"target\": \"SNAT\", \
|
||
\"to\": \"10.10.10.1\", \
|
||
\"i_device\": \"\", \
|
||
\"o_device\": \"\", \
|
||
\"match\": \"mark\", \
|
||
\"match_info\": \"0x64\" \
|
||
}, \
|
||
{ \
|
||
\"action\": 0,\
|
||
\"target\": \"SNAT\", \
|
||
\"id\": 100 \
|
||
}, \
|
||
{ \
|
||
\"action\": 0,\
|
||
\"target\": \"SNAT\", \
|
||
\"id\": 1 \
|
||
}, \
|
||
{ \
|
||
\"action\": 0,\
|
||
\"target\": \"SNAT\", \
|
||
\"id\": 1 \
|
||
}, \
|
||
{ \
|
||
\"action\": 0,\
|
||
\"target\": \"SNAT\", \
|
||
\"id\": 1 \
|
||
}, \
|
||
{ \
|
||
\"action\": 0,\
|
||
\"target\": \"SNAT\", \
|
||
\"id\": 1 \
|
||
},\
|
||
]}";
|
||
|
||
/*==============================================================================*
|
||
* MACRO |
|
||
*==============================================================================*/
|
||
|
||
#define FILE_FGETS(BUF, MAX_LEN, FP) while(fgets(BUF, MAX_LEN, FP) != NULL)
|
||
#define FILL_IPT_OPTION(OPTION, MAX) \
|
||
strncpy(conf->OPTION, *(_argv + _optind++), (MAX) - 1)
|
||
#define CMP_IPT_OPTION(OPTION) \
|
||
{ if (strcmp(condition->OPTION, "") != 0 && \
|
||
strcmp(condition->OPTION, _argv[_optind]) != 0) { \
|
||
*match = FAIL; goto pass;} \
|
||
}
|
||
|
||
#define isempty_str(ptr) (ptr[0] == '\0') // 字符串判空
|
||
#define isempty_int(v) (v == 0x7fffffff) // int数据未赋值判别
|
||
#define add_space(s) strncat(s, " ", 1)
|
||
#define is_snat(ptr) (strcmp(ptr->target, "SNAT") == 0)
|
||
#define is_dnat(ptr) (strcmp(ptr->target, "DNAT") == 0)
|
||
#define is_masquerade(ptr) (strcmp(ptr->target, "MASQUERADE") == 0)
|
||
#define set_chain(ptr, c) strcpy(ptr->chain, c)
|
||
#define get_chain(ptr) (ptr->chain)
|
||
#define get_id(ptr) (ptr->id)
|
||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||
|
||
/*
|
||
* fopen的包裹,包含异常处理
|
||
* parameters:
|
||
* @__filename: fopen文件路径
|
||
* @__mode: fopen打开模式
|
||
*/
|
||
#define Fopen(fp, __filename, __mode, msg) do { \
|
||
fp = fopen(__filename, __mode); \
|
||
if (fp == NULL) { \
|
||
__error_report(msg, -1, "Can't open the iptables-save file!\n"); \
|
||
return NULL; \
|
||
} \
|
||
} while (0)
|
||
|
||
/*
|
||
* cJSON_Parse的包裹,将字符串形式的json转化为cJSON结构,包含异常处理
|
||
* parameters:
|
||
* @json: 字符串形式的json
|
||
* @value: 字符串形式的json数据
|
||
* @msg: 信息返回
|
||
*/
|
||
#define cJSON_Parse_e(json, value, msg) do { \
|
||
json = cJSON_Parse(value); \
|
||
if (!json) { \
|
||
__error_report(msg, -1, "Error before: [%s]\n", cJSON_GetErrorPtr()); \
|
||
return NULL; \
|
||
} \
|
||
} while (0)
|
||
|
||
|
||
#define _IPT_STR_ITEM_TOJSON(CE, E) do { \
|
||
if (*(conf->CE) != 0) \
|
||
cJSON_AddStringToObject(obj, #E, conf->CE); \
|
||
/* else cJSON_AddNullToObject(obj, #E); */ \
|
||
} while (0)
|
||
|
||
#define _IPT_INT_ITEM_TOJSON(CE, E) do { \
|
||
if (conf->CE != 0) \
|
||
cJSON_AddNumberToObject(obj, #E, conf->CE); \
|
||
/* else cJSON_AddNullToObject(obj, #E); */ \
|
||
} while (0)
|
||
|
||
#define _JSON_STR_TO_IPT_ITEM(E, CE, MAX) do { \
|
||
cJSON *__json = cJSON_GetObjectItem(json, #E); \
|
||
if (__json) { \
|
||
if (strlen(__json->valuestring) >= MAX) {*ret = RET_INPUTERR; goto err;} \
|
||
else strcpy(conf->CE, __json->valuestring); \
|
||
} \
|
||
else strcpy(conf->CE, ""); \
|
||
} while (0)
|
||
|
||
#define _JSON_INT_TO_IPT_ITEM(E) do { \
|
||
cJSON *__json = cJSON_GetObjectItem(json, #E); \
|
||
if (__json) conf->E = __json->valueint; \
|
||
else conf->E = 0x7fffffff;\
|
||
} while (0)
|
||
|
||
// 宏: str拼接到字符串,并防止拼接越界
|
||
#define strcat_str_free_count(des, src) do { \
|
||
int len = strlen(src); \
|
||
if (free_space <= len) {ret = RET_NOMEM; goto err;} \
|
||
else { \
|
||
strncat(des, src, free_space-1); \
|
||
free_space -= len; \
|
||
} \
|
||
} while (0)
|
||
|
||
// 宏: 字段正则检查
|
||
#define _REG_CHK(reg, E) do { \
|
||
int status = __regex_match(reg, conf->E); \
|
||
if(status != 0) { \
|
||
__error_report(msg, current_id, "\"%s: %s\" is not vaild!", #E, conf->E); \
|
||
return FAIL; \
|
||
} \
|
||
} while (0)
|
||
|
||
// 宏: int拼接到字符串,并防止拼接越界
|
||
#define strcat_int_free_count(des, src) do { \
|
||
char s[21]; \
|
||
if (src == -1) s[0] = '\0'; else itoa(src, s); \
|
||
int len = strlen(s); \
|
||
if (free_space <= len) {ret = RET_NOMEM; goto err;} \
|
||
else { \
|
||
strncat(des, s, free_space-1); \
|
||
free_space -= len; \
|
||
} \
|
||
} while (0)
|
||
|
||
|
||
/*
|
||
* 宏: 命令拼接
|
||
* @rule: 已完成拼接命令
|
||
* @E: 待拼接字段
|
||
* @EX: 拓展拼接字符串
|
||
* @type: 带拼接字段类型,可选str,int
|
||
*/
|
||
#define splice_item(rule, E, CE, EX, type) do { \
|
||
enum ipt_config_item item = E; \
|
||
if (!isempty_##type(conf->CE)) { \
|
||
strcat_str_free_count(rule, __prefix[item]); \
|
||
if (!isempty_str(EX)) { \
|
||
strcat_str_free_count(rule, EX); \
|
||
strcat_str_free_count(rule, " "); \
|
||
} \
|
||
strcat_##type##_free_count(rule, conf->CE); \
|
||
} \
|
||
} while (0)
|
||
|
||
/*
|
||
* malloc宏,异常信息处理通过chk_malloc_oom_handler,goto MEMerr
|
||
* parameters:
|
||
* @ptr: 待分配指针
|
||
* @struct: 指针结构类型
|
||
* @size: 分配空间字节数
|
||
* @ret: ret_code返回码
|
||
* @msg: 信息返回
|
||
*/
|
||
#define __chk_malloc(ptr, struct, size, ret, msg) do { \
|
||
ptr = (struct)malloc(size); \
|
||
if(!(ptr)) { \
|
||
if(msg) chk_malloc_oom_handler(size, msg);\
|
||
ret = RET_NOMEM; \
|
||
goto MEMerr; \
|
||
} \
|
||
} while (0)
|
||
|
||
|
||
#define xfree(X) do{ \
|
||
if(X) { \
|
||
free(X); \
|
||
X = NULL; \
|
||
} \
|
||
} while(0)
|
||
|
||
/*==============================================================================*
|
||
* VARIABLES |
|
||
*==============================================================================*/
|
||
|
||
// 全局返回信息最大长度
|
||
static int free_space = MAX_ERR_MSG;
|
||
// 当前执行的命令id
|
||
static int current_id = -1;
|
||
|
||
static char *_ip_regex = "^(((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})\
|
||
(\\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}(/([0-9]|\\.){1,15}){0,1}){0,1}$";
|
||
|
||
static char *_id_regex = "^([0-9]{0,5})$";
|
||
static char *_port_regex = "^([0-9]{0,5})$";
|
||
static char *_prot_regex = "^([0-9a-zA-Z]|-){0,15}$";
|
||
static char *_device_regex = "^([0-9a-zA-Z]|-){0,15}$";
|
||
|
||
static char *_addr_regex = "^((((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})\
|
||
(\\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3})(-\
|
||
(((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})\
|
||
(\\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3})){0,1}\
|
||
(:[0-9]{0,5}(-[0-9]{0,5}){0,1}){0,1}){0,1}$";
|
||
|
||
static char *_match_regex = "^(mark){0,1}$";
|
||
static char *_match_info_regex = "^[0-9]{0,4}$";
|
||
|
||
typedef void *(*jsonfunc)(cJSON *json_arr, int *output_len, ret_code *ret, char **msg);
|
||
|
||
// iptables 命令参数拼接前缀
|
||
static char * __prefix[IPT_PARANUM] = {
|
||
" -D ",
|
||
" -I ",
|
||
" -A ",
|
||
" -s ",
|
||
" -d ",
|
||
" -p ",
|
||
" --sport ",
|
||
" --dport ",
|
||
" -i ",
|
||
" -o ",
|
||
" -m ",
|
||
" --",
|
||
" -j ",
|
||
" --to-"
|
||
};
|
||
|
||
static char *__field_match[NF_PARANUM] = {
|
||
"src=",
|
||
"dst=",
|
||
"sport=",
|
||
"dport=",
|
||
"src=",
|
||
"dst=",
|
||
"sport=",
|
||
"dport=",
|
||
};
|
||
|
||
// json字段枚举,action不参与命令拼接
|
||
enum ipt_config_item {
|
||
del, insert, chain, source, destination, prot, sport, dport, i_device,
|
||
o_device, match, match_info, target, to
|
||
};
|
||
|
||
// set配置枚举
|
||
enum action {
|
||
DELETE, SET, SAVE, RESTORE, UNKNOWN
|
||
};
|
||
|
||
/*==============================================================================*
|
||
* PRIVATE-API |
|
||
*==============================================================================*/
|
||
|
||
// 从iptables-save配置文件读取iptables中nat的配置信息,可指定范围
|
||
iptables_rule *__read_iptables_conf(const char *filename, int *output_len, int begin,
|
||
int offset, ret_code *ret, char **msg);
|
||
|
||
// 使用一条ipt_config结构配置信息,拼接成linux命令
|
||
ret_code __command_splice(struct ipt_config *conf, iptables_rule rule, char **msg);
|
||
|
||
// 按顺序解析参数序列中的参数标记
|
||
uchar __extract_parm(int *_optind, const int _argc, char **_argv);
|
||
// 将字符串按空格(space)拆分成字符串指针,可处理连续空格
|
||
char **__str2str_array(const char *str, int *output_len);
|
||
// 将字符串按指定分隔符拆分成字符串指针,可处理连续分隔符
|
||
char** split(const char * const targetString, const char * const delimiter,int * const length);
|
||
// 将int整数转化成char*字符串
|
||
void itoa(int a, char s[]);
|
||
// ipt_config结构的配置信息合法性检查,完成缺省配置推导
|
||
boolean __iptconfig_chk(struct ipt_config *conf, char **msg);
|
||
// 将一条ipt_config类型的配置信息转化为json数据
|
||
ret_code __ipt_config_tojson(cJSON *root, const struct ipt_config *conf);
|
||
|
||
// 将字符串格式的json配置信息解析为多种数据类型
|
||
void *__jsontxt_to_struct(const char *json_text, int *output_len, jsonfunc func,
|
||
ret_code *ret, char **msg);
|
||
// 将nat模块使用的cjson配置信息解析为ipt_config类型
|
||
void *__cjsonarr_to_ipt_config(cJSON *json_arr, int *output_len,
|
||
ret_code *ret, char **msg);
|
||
// 将nat模块使用的cjson配置信息解析为range_ipt_config类型
|
||
void *__cjsonarr_to_range_ipt_config(cJSON *json_arr, int *output_len,
|
||
ret_code *ret, char **msg);
|
||
|
||
// 解析ipt_config的action字段
|
||
enum action __parse_action(const struct ipt_config * const conf);
|
||
// 解析一条字符串形式的nat配置信息,并与规则进行匹配
|
||
ret_code __ipt_conf_parse(const iptables_rule rule, const struct ipt_config *condition,
|
||
boolean *match, struct ipt_config *conf);
|
||
|
||
// 从/proc/net/nf_conntrack中读取连接跟踪信息,暂不使用
|
||
char **__read_nf_conntrack(const char *filename, int *output_len,
|
||
ret_code *ret, char **msg);
|
||
// 连接跟踪信息解析,暂不使用,未完成
|
||
ret_code __nf_conntrack_parse(const char *conn, nf_conntrack *conf);
|
||
|
||
// 异常处理函数
|
||
char *__error_report(char** msg, int id, char *fmt, ...)
|
||
__attribute__((format(printf, 3, 4)));
|
||
|
||
int __regex_match(char* pattern, char* buf);
|
||
|
||
// 字符串指针(char**)释放函数
|
||
void __free_dptr_char(char ***ptr, int len);
|
||
|
||
/*==============================================================================*
|
||
* FUNCTION |
|
||
*==============================================================================*/
|
||
|
||
/*
|
||
* 异常处理函数
|
||
* parameters:
|
||
* @msg: 异常信息返回
|
||
* @id: 命令序号
|
||
* @fmt, ...
|
||
*
|
||
* return: 错误信息字符串
|
||
*/
|
||
char* __error_report (char **msg, int id, char *fmt, ...) {
|
||
if (*msg == NULL) return NULL;
|
||
char _msg_head[MAX_LINE_LEN - 1];
|
||
char _msg_tail[MAX_LINE_LEN - 30];
|
||
va_list va;
|
||
|
||
// 使用宏strcat_str_free_count,不返回
|
||
ret_code ret;
|
||
|
||
va_start(va, fmt);
|
||
vsnprintf(_msg_tail, MAX_LINE_LEN - 30, fmt, va);
|
||
va_end(va);
|
||
|
||
snprintf(_msg_head, MAX_LINE_LEN - 1, "[err] JSON id: %03d, msg:", id);
|
||
strcat_str_free_count(_msg_head, _msg_tail);
|
||
if (_msg_head[strlen(_msg_head) - 1] != '\n') {
|
||
strcat_str_free_count(_msg_head, "\n");
|
||
}
|
||
|
||
strcat_str_free_count(*msg, _msg_head);
|
||
//printf("%s\n", *msg);
|
||
|
||
err:
|
||
return NULL;
|
||
}
|
||
|
||
int __regex_match(char* pattern, char* buf) {
|
||
int status,i;
|
||
regmatch_t pmatch[1];
|
||
const size_t nmatch=1;
|
||
regex_t reg;
|
||
|
||
//编译正则模式
|
||
regcomp(®, pattern, REG_EXTENDED|REG_NEWLINE);
|
||
//执行正则表达式和缓存的比较
|
||
status=regexec(®, buf, nmatch, pmatch, 0);
|
||
|
||
regfree(®);
|
||
return status;
|
||
}
|
||
|
||
|
||
/*
|
||
* 将int整数转化成char*字符串
|
||
* parameters:
|
||
* @a: 待转化int类型整数
|
||
* @s: 返回转化后字符串数组
|
||
*
|
||
* return: void
|
||
*/
|
||
void itoa(int a, char s[]) {
|
||
snprintf(s, 20, "%d", a);
|
||
}
|
||
|
||
static void chk_malloc_default_oom(size_t size, char **msg) {
|
||
__error_report(msg, -1, "malloc: out of memory trying to allocate %zu bytes\n", size);
|
||
//abort();
|
||
}
|
||
|
||
static void(*chk_malloc_oom_handler)(size_t, char**) = chk_malloc_default_oom;
|
||
|
||
|
||
/*
|
||
* 字符串指针(char**)释放函数
|
||
* parameters:
|
||
* @ptr: 待释放字符串指针
|
||
* @len: 所包含一维指针个数
|
||
*
|
||
* return: 成功则返回void*
|
||
*/
|
||
void __free_dptr_char(char ***ptr, int len) {
|
||
int i = 0;
|
||
if (*ptr == NULL) return;
|
||
for ( ; i < len; ++i) xfree((*ptr)[i]);
|
||
xfree(*ptr);
|
||
}
|
||
|
||
/*
|
||
* linux系统命令执行函数
|
||
* parameters:
|
||
* @cmd: char*形式的linux命令
|
||
* @id: 命令执行序号
|
||
* @msg: 信息返回
|
||
*
|
||
* return: ret_code返回码
|
||
*/
|
||
ret_code run_command( char *const cmd, char **msg) {
|
||
char* result = NULL;
|
||
FILE *fpRead = NULL;
|
||
ret_code ret = RET_OK;
|
||
char buf[MAX_LINE_LEN] = {0};
|
||
//char result[MAX_LINE_LEN] = {0};
|
||
if(!cmd){
|
||
goto pass;
|
||
}
|
||
__chk_malloc(result, char*, MAX_LINE_LEN * sizeof(char), ret, msg);
|
||
result = (char *)malloc(MAX_LINE_LEN);
|
||
if(!result){
|
||
goto pass;
|
||
}
|
||
//printf("1cmd: addr is %x, content is %s\n", cmd, cmd);
|
||
//printf("1result: addr is %x, content is %s\n", result, result);
|
||
memset(result, 0, MAX_LINE_LEN);
|
||
printf("%s\n", cmd);
|
||
// 执行cmd命令,fpRead指向命令执行后的shell信息
|
||
fpRead = popen(cmd, "r");
|
||
if (fpRead == NULL) goto pass;
|
||
|
||
FILE_FGETS(buf, MAX_LINE_LEN - 1,fpRead) {
|
||
strncat(result, buf, MAX_LINE_LEN - 1);
|
||
// 只返回第一行错误信息
|
||
break;
|
||
}
|
||
//printf("2cmd: addr is %x, content is %s\n", cmd, cmd);
|
||
//printf("2result: addr is %x, content is %s\n", result, result);
|
||
if (!isempty_str(result)) {
|
||
__error_report(msg, current_id, "%s", result);
|
||
ret = RET_ERR;
|
||
goto pass;
|
||
}
|
||
|
||
|
||
MEMerr:
|
||
pass:
|
||
if(fpRead!=NULL)
|
||
pclose(fpRead);
|
||
|
||
xfree(result);
|
||
return ret;
|
||
}
|
||
|
||
|
||
/*
|
||
* 从iptables-save配置文件读取iptables中nat的配置信息,可指定范围
|
||
* parameters:
|
||
* @filename: iptables-save配置文件路径
|
||
* @output_len: 返回值中nat配置信息条目数,无需初始化
|
||
* @ret: ret_code返回码
|
||
* @begin: 指定nat配置开始位置
|
||
* @offset: 指定nat配置结束位置,相对begin偏移量;若为-1,则读取到nat配置结束
|
||
* @msg: 信息返回
|
||
*
|
||
* return: 包含nat配置信息的二级指针
|
||
*/
|
||
iptables_rule *__read_iptables_conf(const char *filename, int *output_len, int begin,
|
||
int offset, ret_code *ret, char **msg) {
|
||
FILE *fp = NULL;
|
||
char buf[MAX_LINE_LEN];
|
||
int nat_start_flag = 0, nat_offset = -1;
|
||
int lines = 0, count = 0, i = 0;
|
||
iptables_rule *__rules = NULL;
|
||
|
||
*output_len = 0;
|
||
Fopen(fp, filename, "r", msg);
|
||
|
||
FILE_FGETS(buf, MAX_LINE_LEN - 1,fp) {
|
||
if (strncmp("*nat", buf, 4) == 0) {
|
||
nat_start_flag = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 定位nat配置信息在iptables-save文件中的起止位置,获取配置条目数count
|
||
if (nat_offset == -1) nat_offset = ftell(fp);
|
||
if (nat_start_flag == 0) {
|
||
fclose(fp);
|
||
return NULL;
|
||
}
|
||
else { // 定位nat配置结束位置
|
||
FILE_FGETS(buf, MAX_LINE_LEN - 1,fp) {
|
||
if (strncmp("COMMIT", buf, 6) == 0) break;
|
||
count += 1;
|
||
}
|
||
}
|
||
|
||
if (offset < 0) offset = count;
|
||
*output_len = max(min(count - begin, offset), 0);
|
||
if (*output_len == 0) goto pass;
|
||
|
||
__chk_malloc(__rules, iptables_rule*, sizeof(iptables_rule) * (*output_len), *ret, msg);
|
||
|
||
// FILE指针重置到nat部分起始位置
|
||
fseek(fp, nat_offset, SEEK_SET);
|
||
FILE_FGETS(buf, MAX_LINE_LEN - 1, fp) {
|
||
if (i == count || i == begin + offset) break;
|
||
if (i < begin) continue;
|
||
__chk_malloc(__rules[i], iptables_rule, sizeof(char) * MAX_LINE_LEN, *ret, msg);
|
||
memset(__rules[i], 0, sizeof(char)*MAX_LINE_LEN);
|
||
|
||
strncpy(__rules[i], buf, MAX_LINE_LEN - 1);
|
||
i += 1;
|
||
}
|
||
|
||
if(fp!=NULL)
|
||
fclose(fp);
|
||
return __rules;
|
||
|
||
MEMerr:
|
||
__free_dptr_char(&__rules, *output_len);
|
||
*output_len = 0;
|
||
pass:
|
||
if(fp!=NULL)
|
||
fclose(fp);
|
||
return NULL;
|
||
}
|
||
|
||
/*
|
||
* 从/proc/net/nf_conntrack中读取连接跟踪信息,暂不使用
|
||
* parameters:
|
||
* @filename: iptables-save配置文件路径
|
||
* @output_len: 返回值中nat配置信息条目数,无需初始化
|
||
* @ret: ret_code返回码
|
||
* @msg: 信息返回
|
||
*
|
||
* return: 包含连接跟踪信息的二级指针
|
||
*/
|
||
char **__read_nf_conntrack(const char *filename, int *output_len,
|
||
ret_code *ret, char **msg) {
|
||
FILE *fp = NULL;
|
||
int count = 0, i = 0;
|
||
char ch, buf[MAX_LINE_LEN];
|
||
char **result = NULL;
|
||
|
||
Fopen(fp, filename, "r", msg);
|
||
|
||
while((ch = fgetc(fp)) != EOF) {
|
||
if(ch == '\n') count++;
|
||
}
|
||
|
||
__chk_malloc(result, char**, sizeof(char*) * count, *ret, msg);
|
||
|
||
fseek(fp, 0, SEEK_SET);
|
||
FILE_FGETS(buf, MAX_LINE_LEN - 1, fp) {
|
||
__chk_malloc(result[i], char*, MAX_LINE_LEN, *ret, msg);
|
||
memset(result[i], 0, MAX_LINE_LEN);
|
||
|
||
strncpy(result[i], buf, MAX_LINE_LEN - 1);
|
||
if (++i == count) break;
|
||
}
|
||
|
||
*output_len = count;
|
||
return result;
|
||
|
||
MEMerr:
|
||
__free_dptr_char(&result, count);
|
||
|
||
if(fp!=NULL)
|
||
fclose(fp);
|
||
return NULL;
|
||
}
|
||
|
||
/*
|
||
* 将字符串按空格(space)拆分成字符串指针,可处理连续空格
|
||
* parameters:
|
||
* @str: 待拆分字符串
|
||
* @output_len: 拆分后的字符串数目,初始化0
|
||
*/
|
||
char **__str2str_array(const char *str, int *output_len) {
|
||
char * ch1 = "\n";
|
||
char * ch2 = " ";
|
||
int length1 = 0;
|
||
int length2 = 0;
|
||
|
||
char **result1 = split(str, ch1, &length1);
|
||
if (!result1) return NULL;
|
||
|
||
char **result2 = split(result1[0], ch2, &length2);
|
||
|
||
*output_len = length2;
|
||
__free_dptr_char(&result1, length1);
|
||
return result2;
|
||
}
|
||
|
||
/*
|
||
* 将字符串按指定分隔符拆分成字符串指针,可处理连续分隔符
|
||
* parameters:
|
||
* @targetString: 待拆分字符串
|
||
* @delimiter: 指定分隔符
|
||
* @length: 拆分后的字符串数目,初始化0
|
||
*/
|
||
char **split(const char * const targetString, const char * const delimiter,
|
||
int * const length){
|
||
|
||
*length = 0;
|
||
char ** resultString = NULL;
|
||
char inputString[strlen(targetString) + 1];
|
||
strcpy(inputString,targetString);
|
||
|
||
char inputDelimiter[strlen(delimiter) + 1];
|
||
strcpy(inputDelimiter,delimiter);
|
||
|
||
char * splitedString = strtok(inputString, inputDelimiter);
|
||
while (splitedString){
|
||
(*length)++;
|
||
char *resultChar = NULL;
|
||
|
||
// 不使用__chk_malloc,将报错延迟到命令解析函数
|
||
resultChar = malloc(strlen(splitedString) + 1);
|
||
if (!resultChar) {
|
||
__free_dptr_char(&resultString, *length - 1);
|
||
return NULL;
|
||
}
|
||
|
||
strcpy(resultChar,splitedString);
|
||
resultString = realloc(resultString, (*length) * sizeof(char *));
|
||
if (!resultString) {
|
||
__free_dptr_char(&resultString, *length);
|
||
return NULL;
|
||
}
|
||
|
||
resultString[(*length) - 1] = resultChar;
|
||
|
||
splitedString = strtok(NULL, delimiter);
|
||
}
|
||
|
||
return resultString;
|
||
}
|
||
|
||
|
||
/*
|
||
* 按顺序解析参数序列中的参数标记
|
||
* parameters:
|
||
* @_optind: 正在处理的参数在参数序列中的位置, 函数返回前该值+1,指向下一参数
|
||
* @argc: 参数数目
|
||
* @argv: 参数序列指针
|
||
*
|
||
* return: 返回unsigned char类型的唯一参数标记
|
||
*/
|
||
uchar __extract_parm(int *_optind, const int _argc, char **_argv) {
|
||
char *_locate_2 = NULL;
|
||
|
||
// 当前参数位置超过参数序列中参数数目
|
||
if (*_optind >= _argc) return FAIL;
|
||
if (**(_argv + *_optind) == '-') {
|
||
//参数标记前只有一个“-”
|
||
if(*(*(_argv + *_optind) + 1) != '-') {
|
||
return *(*(_argv + (*_optind)++) + 1);
|
||
}
|
||
// 遇到两个连续的“--”
|
||
else {
|
||
_locate_2 = *(_argv + (*_optind)++) + 2;
|
||
|
||
// 非单字符参数标记重新映射
|
||
if (strcmp(_locate_2, "to-destination") == 0 || \
|
||
strcmp(_locate_2, "to-source") == 0) return 128;
|
||
if (strcmp(_locate_2, "sport") == 0) return 129;
|
||
if (strcmp(_locate_2, "dport") == 0) return 130;
|
||
if (strcmp(_locate_2, "mark") == 0) return 131;
|
||
|
||
else return FAIL;
|
||
}
|
||
}
|
||
else return FAIL;
|
||
}
|
||
|
||
/*
|
||
* 解析一条字符串形式的nat配置信息,并与规则进行匹配
|
||
* parameters:
|
||
* @rule: 一条字符串形式的nat配置信息
|
||
* @condition: 匹配规则
|
||
* @match: 若与condition匹配成功,则赋值为success,否则fail
|
||
* @conf: 返回指向解析结果的ipt_config指针,需要预分配空间
|
||
*
|
||
* return: ret_code返回码
|
||
*/
|
||
ret_code __ipt_conf_parse(const iptables_rule rule, const struct ipt_config *condition,
|
||
boolean *match, struct ipt_config *conf) {
|
||
int _optind = 0, _argc;
|
||
uchar option;
|
||
ret_code ret = RET_OK;
|
||
|
||
// 将字符串格式的配置信息分解为参数序列
|
||
// argv: 参数序列,argc: argv中参数个数
|
||
char **_argv = __str2str_array(rule, &_argc);
|
||
if (!_argv) {
|
||
ret = RET_NOMEM;
|
||
goto MEMerr;
|
||
}
|
||
|
||
*match = SUCCESS;
|
||
while(option = __extract_parm(&_optind, _argc, _argv)) {
|
||
if (_optind >= _argc) break;
|
||
switch(option) {
|
||
case '!':
|
||
// to do
|
||
break;
|
||
|
||
case 'A':
|
||
CMP_IPT_OPTION(chain);
|
||
FILL_IPT_OPTION(chain, MAX_CHAIN);
|
||
|
||
break;
|
||
|
||
case 'd':
|
||
CMP_IPT_OPTION(destination);
|
||
FILL_IPT_OPTION(destination, MAX_ADDR);
|
||
break;
|
||
|
||
case 's':
|
||
CMP_IPT_OPTION(source);
|
||
FILL_IPT_OPTION(source, MAX_ADDR);
|
||
break;
|
||
|
||
case 'i':
|
||
CMP_IPT_OPTION(i_device);
|
||
FILL_IPT_OPTION(i_device, MAX_DEVICE);
|
||
break;
|
||
|
||
case 'o':
|
||
CMP_IPT_OPTION(o_device);
|
||
FILL_IPT_OPTION(o_device, MAX_DEVICE);
|
||
break;
|
||
|
||
case 'p':
|
||
CMP_IPT_OPTION(prot);
|
||
FILL_IPT_OPTION(prot, MAX_PROT);
|
||
break;
|
||
|
||
case 'j':
|
||
//CMP_IPT_OPTION(target);
|
||
FILL_IPT_OPTION(target, MAX_TARGET);
|
||
break;
|
||
|
||
case 128:
|
||
CMP_IPT_OPTION(to);
|
||
FILL_IPT_OPTION(to, MAX_ADDR);
|
||
break;
|
||
|
||
case 129:
|
||
CMP_IPT_OPTION(sport);
|
||
FILL_IPT_OPTION(sport, MAX_PORT);
|
||
break;
|
||
|
||
case 130:
|
||
CMP_IPT_OPTION(dport);
|
||
FILL_IPT_OPTION(dport, MAX_PORT);
|
||
break;
|
||
|
||
case 'm':
|
||
CMP_IPT_OPTION(match);
|
||
FILL_IPT_OPTION(match, MAX_MATCH);
|
||
break;
|
||
|
||
case 131:
|
||
CMP_IPT_OPTION(match_info);
|
||
FILL_IPT_OPTION(match_info, MAX_MATCH_INFO);
|
||
break;
|
||
|
||
default:
|
||
_optind++;
|
||
break;
|
||
}
|
||
}
|
||
pass:
|
||
__free_dptr_char(&_argv, _argc);
|
||
|
||
MEMerr:
|
||
return ret;
|
||
}
|
||
|
||
// 连接跟踪信息解析,暂不使用,未完成
|
||
ret_code __nf_conntrack_parse(const char *conn, nf_conntrack *conf) {
|
||
int _argc = 0, i = 0, match_id = 0;
|
||
ret_code ret = RET_OK;
|
||
char **_argv = __str2str_array(conn, &_argc);
|
||
|
||
if (!_argv) {
|
||
ret = RET_NOMEM;
|
||
goto MEMerr;
|
||
}
|
||
|
||
strncpy(conf->prot, _argv[2], MAX_PROT - 1);
|
||
for (i = 3; i < _argc; ++i) {
|
||
if (strncmp(_argv[i], __field_match[match_id],
|
||
strlen(__field_match[match_id])) == 0) {
|
||
// TO DO
|
||
++match_id;
|
||
}
|
||
|
||
}
|
||
|
||
__free_dptr_char(&_argv, _argc);
|
||
|
||
MEMerr:
|
||
return ret;
|
||
}
|
||
|
||
// 解析ipt_config的action字段
|
||
enum action __parse_action(const struct ipt_config * const conf) {
|
||
enum action act;
|
||
|
||
if ((strcmp(conf->action, "ADD") == 0)) act = SET;
|
||
else if ((strcmp(conf->action, "DEL") == 0)) act = DELETE;
|
||
else if ((strcmp(conf->action, "SAVE") == 0)) act = SAVE;
|
||
else if ((strcmp(conf->action, "RESTORE") == 0)) act = RESTORE;
|
||
else act = UNKNOWN;
|
||
|
||
return act;
|
||
}
|
||
|
||
/*
|
||
* 将nat模块使用的cjson配置信息解析为ipt_config类型
|
||
* parameters:
|
||
* @json_arr: 待解析cjson配置信息
|
||
* @output_len: 返回值中ipt_config配置信息条数,赋值0
|
||
* @ret: ret_code返回码
|
||
* @msg: 返回信息
|
||
*
|
||
* return: 指向ipt_config格式配置信息的指针,可能包含多条配置信息
|
||
*/
|
||
void *__cjsonarr_to_ipt_config(cJSON *json_arr, int *output_len,
|
||
ret_code *ret, char **msg) {
|
||
size_t json_arr_size, i;
|
||
struct ipt_config *conf = NULL, *conf_start = NULL;
|
||
cJSON *json = NULL;
|
||
|
||
json_arr_size = cJSON_GetArraySize(json_arr);
|
||
__chk_malloc(conf, struct ipt_config*, sizeof(*conf) * json_arr_size, *ret, msg);
|
||
memset(conf, 0, json_arr_size * sizeof(struct ipt_config));
|
||
conf_start = conf;
|
||
|
||
for (i = 0; i < json_arr_size; ++i, ++conf) {
|
||
json = cJSON_GetArrayItem(json_arr, i);
|
||
//__JSON_STR_TO_IPT_ITEM(chain, MAX_CHAIN);
|
||
_JSON_STR_TO_IPT_ITEM(action, action, MAX_ACTION);
|
||
_JSON_STR_TO_IPT_ITEM(id, id, MAX_ID);
|
||
_JSON_STR_TO_IPT_ITEM(target, target, MAX_TARGET);
|
||
_JSON_STR_TO_IPT_ITEM(prot, prot, MAX_PROT);
|
||
_JSON_STR_TO_IPT_ITEM(source, source, MAX_ADDR);
|
||
_JSON_STR_TO_IPT_ITEM(destination, destination, MAX_ADDR);
|
||
_JSON_STR_TO_IPT_ITEM(sport, sport, MAX_PORT);
|
||
_JSON_STR_TO_IPT_ITEM(dport, dport, MAX_PORT);
|
||
_JSON_STR_TO_IPT_ITEM(to, to, MAX_ADDR);
|
||
|
||
_JSON_STR_TO_IPT_ITEM(device, i_device, MAX_DEVICE);
|
||
_JSON_STR_TO_IPT_ITEM(device, o_device, MAX_DEVICE);
|
||
|
||
_JSON_STR_TO_IPT_ITEM(match, match, MAX_MATCH);
|
||
_JSON_STR_TO_IPT_ITEM(match_info, match_info, MAX_MATCH_INFO);
|
||
|
||
}
|
||
goto pass;
|
||
err:
|
||
__error_report(msg, i, "json item is too long to save in ipt_config.");
|
||
MEMerr:
|
||
xfree(conf_start);
|
||
pass:
|
||
*output_len = json_arr_size;
|
||
|
||
return conf_start;
|
||
}
|
||
|
||
/*
|
||
* 将nat模块使用的cjson配置信息解析为range_ipt_config类型
|
||
* parameters:
|
||
* @json_arr: 待解析cjson配置信息
|
||
* @output_len: 返回值中range_ipt_config配置信息条数,赋值0
|
||
* @ret: ret_code返回码
|
||
* @msg: 返回信息
|
||
*
|
||
* return: 指向range_ipt_config格式配置信息的指针,可能包含多条配置信息
|
||
*/
|
||
void *__cjsonarr_to_range_ipt_config(cJSON *json_arr, int *output_len,
|
||
ret_code *ret, char **msg){
|
||
size_t json_arr_size, i;
|
||
struct ipt_config *conf = NULL, *conf_start = NULL;
|
||
struct range_ipt_config *rwconf = NULL, *rwconf_start = NULL;
|
||
cJSON *json = NULL, *__json = NULL;
|
||
|
||
json_arr_size = cJSON_GetArraySize(json_arr);
|
||
__chk_malloc(rwconf, struct range_ipt_config*, sizeof(*rwconf) * json_arr_size, *ret, msg);
|
||
memset(rwconf, 0, json_arr_size * sizeof(struct range_ipt_config));
|
||
rwconf_start = rwconf;
|
||
|
||
__chk_malloc(conf, struct ipt_config*, sizeof(*conf) * json_arr_size, *ret, msg);
|
||
memset(conf, 0, json_arr_size * sizeof(struct ipt_config));
|
||
conf_start = conf;
|
||
|
||
conf = __cjsonarr_to_ipt_config(json_arr, output_len, ret, msg);
|
||
|
||
for (i = 0; i < json_arr_size; ++i, ++conf, ++rwconf) {
|
||
memcpy(&(rwconf->conf), conf, sizeof(struct ipt_config));
|
||
|
||
json = cJSON_GetArrayItem(json_arr, i);
|
||
__json = cJSON_GetObjectItem(json, "begin");
|
||
if (__json) rwconf->begin = atoi(__json->valuestring);
|
||
else {
|
||
*ret = RET_INPUTERR;
|
||
goto MEMerr;
|
||
}
|
||
|
||
json = cJSON_GetArrayItem(json_arr, i);
|
||
__json = cJSON_GetObjectItem(json, "offset");
|
||
if (__json) rwconf->offset = atoi(__json->valuestring);
|
||
else {
|
||
*ret = RET_INPUTERR;
|
||
goto MEMerr;
|
||
}
|
||
}
|
||
goto pass;
|
||
err:
|
||
__error_report(msg, i, "json item is too long to save in range_ipt_config.");
|
||
MEMerr:
|
||
xfree(rwconf_start);
|
||
pass:
|
||
xfree(conf_start);
|
||
*output_len = json_arr_size;
|
||
|
||
return rwconf_start;
|
||
}
|
||
|
||
/*
|
||
* 将字符串格式的json配置信息解析为多种数据类型
|
||
* parameters:
|
||
* @json_text: 字符串格式的json配置信息
|
||
* @output_len: 返回值中ipt_config配置信息条数,赋值0
|
||
* @func: 指向具体解析方法的函数指针
|
||
* @ret: ret_code返回码
|
||
* @msg: 返回信息
|
||
*
|
||
* return: 指向void*类型配置信息的指针,可能包含多条配置信息
|
||
*/
|
||
void *__jsontxt_to_struct(const char *json_text, int *output_len, jsonfunc func,
|
||
ret_code *ret, char **msg) {
|
||
cJSON *json_all = NULL, *json_arr = NULL;
|
||
void *conf = NULL;
|
||
|
||
*output_len = 0;
|
||
cJSON_Parse_e(json_all, json_text, msg);
|
||
|
||
json_arr = cJSON_GetObjectItem(json_all, "content");
|
||
if (!json_arr) {
|
||
__error_report(msg, -1, "%s", "json without content!");
|
||
*ret = RET_NOMEM;
|
||
goto MEMerr;
|
||
}
|
||
|
||
conf = func(json_arr, output_len, ret, msg);
|
||
|
||
MEMerr:
|
||
cJSON_Delete(json_all);
|
||
return conf;
|
||
}
|
||
|
||
|
||
/*
|
||
* 使用一条ipt_config结构配置信息,拼接成linux命令
|
||
* parameters:
|
||
* @conf: 一条ipt_config结构的的nat配置信息
|
||
* @rule: 返回拼接后的字符串格式linux命令,需要预分配空间
|
||
* @msg: 信息返回
|
||
*
|
||
* return: ret_code返回码
|
||
*/
|
||
ret_code __command_splice(struct ipt_config *conf, iptables_rule rule, char **msg) {
|
||
iptables_rule head = "sudo iptables -t nat";
|
||
size_t free_space = MAX_LINE_LEN;
|
||
enum action option;
|
||
ret_code ret = RET_OK;
|
||
|
||
switch (option = __parse_action(conf)) {
|
||
|
||
// delete
|
||
case DELETE:
|
||
if (!isempty_str(conf->id)) {
|
||
strcat_str_free_count(rule, head);
|
||
splice_item(rule, del, id, get_chain(conf), str);
|
||
}
|
||
else {
|
||
strcpy(conf->id, " ");
|
||
strcat_str_free_count(rule, head);
|
||
splice_item(rule, del, id, get_chain(conf), str);
|
||
goto setmode;
|
||
}
|
||
|
||
break;
|
||
|
||
// set
|
||
case SET:
|
||
strcat_str_free_count(rule, head);
|
||
if (isempty_str(conf->id)) splice_item(rule, chain, chain, "", str);
|
||
else splice_item(rule, insert, id, get_chain(conf), str);
|
||
setmode:
|
||
splice_item(rule, source, source, "", str);
|
||
splice_item(rule, destination, destination, "", str);
|
||
splice_item(rule, prot, prot, "", str);
|
||
splice_item(rule, sport, sport, "", str);
|
||
splice_item(rule, dport, dport, "", str);
|
||
splice_item(rule, i_device, i_device, "", str);
|
||
splice_item(rule, o_device, o_device, "", str);
|
||
splice_item(rule, match, match, "", str);
|
||
splice_item(rule, match_info, match_info, conf->match, str);
|
||
splice_item(rule, target, target, "", str);
|
||
|
||
if (is_snat(conf)) splice_item(rule, to, to, "source", str);
|
||
else if (is_dnat(conf)) splice_item(rule, to, to, "destination", str);
|
||
break;
|
||
|
||
// save
|
||
case SAVE:
|
||
// TO DO
|
||
break;
|
||
|
||
// restore
|
||
case RESTORE:
|
||
// TO DO
|
||
break;
|
||
|
||
default:
|
||
// TO DO
|
||
break;
|
||
err:
|
||
__error_report(msg, current_id, "the iptables command is too long to splice!\n");
|
||
}
|
||
|
||
return ret;
|
||
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* ipt_config结构的配置信息合法性检查,完成缺省配置推导
|
||
* parameters:
|
||
* @conf: 一条ipt_config结构的nat配置信息
|
||
*
|
||
* return: 配置完成且合法,返回SUCCESS
|
||
*/
|
||
boolean __iptconfig_chk(struct ipt_config *conf, char **msg) {
|
||
// TO DO
|
||
enum action option;
|
||
|
||
if (conf == NULL) return FAIL;
|
||
|
||
if (isempty_str(conf->target)) {
|
||
__error_report(msg, current_id, "Blank target is not allowed!\n");
|
||
return FAIL;
|
||
}
|
||
|
||
if (is_snat(conf)) {
|
||
if (isempty_str(conf->to)) strcpy(conf->target, "MASQUERADE");
|
||
set_chain(conf, "POSTROUTING");
|
||
conf->i_device[0] = '\0';
|
||
|
||
}
|
||
else if (is_dnat(conf)) {
|
||
set_chain(conf, "PREROUTING");
|
||
conf->o_device[0] = '\0';
|
||
}
|
||
else if (is_masquerade(conf)) {
|
||
set_chain(conf, "POSTROUTING");
|
||
conf->i_device[0] = '\0';
|
||
}
|
||
else {
|
||
__error_report(msg, current_id, "\"%s\" is not is valid target!\n", conf->target);
|
||
return FAIL;
|
||
}
|
||
|
||
switch (option = __parse_action(conf)) {
|
||
case DELETE:
|
||
if (!isempty_str(conf->id)) {
|
||
_REG_CHK(_id_regex, id);
|
||
}
|
||
else {
|
||
goto setmode;
|
||
}
|
||
break;
|
||
|
||
case SET:
|
||
_REG_CHK(_id_regex, id);
|
||
setmode:
|
||
_REG_CHK(_ip_regex, source);
|
||
_REG_CHK(_ip_regex, destination);
|
||
_REG_CHK(_port_regex, sport);
|
||
_REG_CHK(_port_regex, dport);
|
||
_REG_CHK(_prot_regex, prot);
|
||
_REG_CHK(_device_regex, i_device);
|
||
_REG_CHK(_device_regex, o_device);
|
||
_REG_CHK(_match_regex, match);
|
||
_REG_CHK(_match_info_regex, match_info);
|
||
_REG_CHK(_addr_regex, to);
|
||
break;
|
||
|
||
case SAVE:
|
||
return FAIL;
|
||
break;
|
||
|
||
case RESTORE:
|
||
return FAIL;
|
||
break;
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
/*
|
||
* 使用json数据格式,配置ipables nat
|
||
* parameters:
|
||
* @json: 字符串格式的json配置信息
|
||
* @msg: 信息返回
|
||
*
|
||
* return: ret_code返回码
|
||
*/
|
||
ret_code set_iptables_config(const char *json, char **msg) {
|
||
int len = 0, i;
|
||
iptables_rule rule = NULL;
|
||
ret_code ret = RET_OK;
|
||
struct ipt_config *conf = NULL, *conf_start = NULL;
|
||
|
||
free_space = MAX_ERR_MSG;
|
||
__chk_malloc((*msg), char*, sizeof(char) * free_space, ret, NULL);
|
||
memset(*msg, 0, sizeof(char) * free_space);
|
||
|
||
conf = (struct ipt_config*)__jsontxt_to_struct(json, &len,
|
||
__cjsonarr_to_ipt_config, &ret, msg);
|
||
if (ret != RET_OK) goto err;
|
||
conf_start = conf;
|
||
|
||
for (i = 0; i < len; ++i, ++conf) {
|
||
current_id = i;
|
||
|
||
if (__iptconfig_chk(conf, msg)) {
|
||
__chk_malloc(rule, iptables_rule, MAX_LINE_LEN + 1, ret, msg);
|
||
memset(rule, 0, sizeof(char) * (MAX_LINE_LEN + 1));
|
||
|
||
if ((ret = __command_splice(conf, rule, msg)) != RET_OK) goto err;
|
||
#if 0
|
||
// shell输出拼接后的linux配置命令
|
||
printf("%s\n", rule);
|
||
#endif
|
||
// 错误输出重定向
|
||
strncat(rule, " 2>&1", MAX_LINE_LEN - 1);
|
||
if ((ret = run_command(rule, msg)) != RET_OK) goto err;
|
||
|
||
xfree(rule);
|
||
|
||
}
|
||
else {
|
||
ret = RET_INPUTERR;
|
||
goto err;
|
||
}
|
||
}
|
||
|
||
ret = run_command("sudo iptables-save -t nat > ./iptables-conf.txt 2>&1", msg);
|
||
|
||
MEMerr:
|
||
err:
|
||
xfree(rule);
|
||
xfree(conf_start);
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* 将一条ipt_config类型的配置信息转化为json数据
|
||
* parameters:
|
||
* @root: json数据插入根节点指针
|
||
* @conf: 一条ipt_config类型的配置信息的指针,需要预分配空间
|
||
*
|
||
* return: ret_code返回码
|
||
*/
|
||
ret_code __ipt_config_tojson(cJSON *root, const struct ipt_config *conf) {
|
||
if (root == NULL) return FAIL;
|
||
cJSON *obj = NULL;
|
||
|
||
cJSON_AddItemToArray(root, obj=cJSON_CreateObject());
|
||
//_IPT_INT_ITEM_TOJSON(id);
|
||
_IPT_STR_ITEM_TOJSON(chain, chain);
|
||
_IPT_STR_ITEM_TOJSON(target, target);
|
||
_IPT_STR_ITEM_TOJSON(prot, prot);
|
||
_IPT_STR_ITEM_TOJSON(source, source);
|
||
_IPT_STR_ITEM_TOJSON(destination, destination);
|
||
_IPT_STR_ITEM_TOJSON(sport, sport);
|
||
_IPT_STR_ITEM_TOJSON(dport, dport);
|
||
_IPT_STR_ITEM_TOJSON(to,to);
|
||
_IPT_STR_ITEM_TOJSON(i_device, device);
|
||
_IPT_STR_ITEM_TOJSON(o_device, device);
|
||
|
||
_IPT_STR_ITEM_TOJSON(match, match);
|
||
_IPT_STR_ITEM_TOJSON(match_info, match_info);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
/*
|
||
* 从iptables-save配置文件中,获取json格式的nat配置信息
|
||
* parameters:
|
||
* @__filename: iptables-save配置文件路径
|
||
* @output: 返回字符串类型的json格式nat配置信息,需要预分配空间
|
||
* @outlen: 返回配置信息字符串长度
|
||
* @msg: 信息返回
|
||
*
|
||
* return: ret_code返回码
|
||
*/
|
||
ret_code get_iptables_config(const char *json, const char * __restrict__ __filename,
|
||
char *output, int *outlen, char **msg) {
|
||
cJSON *root = NULL;
|
||
iptables_rule *rules = NULL, *rules_start = NULL;
|
||
struct ipt_config *conf = NULL;
|
||
struct range_ipt_config *rwconf = NULL;
|
||
int len = 0, i;
|
||
int count = 0, offset = 0;
|
||
char* out = NULL;
|
||
free_space = MAX_ERR_MSG;
|
||
boolean match = FAIL;
|
||
ret_code ret = RET_OK;
|
||
|
||
__chk_malloc((*msg), char*, sizeof(char) * free_space, ret, NULL);
|
||
memset(*msg, 0, sizeof(char)*free_space);
|
||
|
||
ret = run_command("sudo iptables-save -t nat > ./iptables-conf.txt 2>&1", msg);
|
||
if (ret != RET_OK) goto err;
|
||
|
||
root = cJSON_CreateArray();
|
||
if (!root) {
|
||
__error_report(msg, -1, "Error before: [%s]\n", cJSON_GetErrorPtr());
|
||
ret = RET_NOMEM;
|
||
goto MEMerr;
|
||
}
|
||
rwconf = (struct range_ipt_config*)__jsontxt_to_struct(json, &len,
|
||
__cjsonarr_to_range_ipt_config, &ret, msg);
|
||
if (ret != RET_OK) goto err;
|
||
|
||
rules = __read_iptables_conf(__filename, &len, 0, -1, &ret, msg);
|
||
rules_start = rules;
|
||
if (!__iptconfig_chk(&(rwconf->conf), msg)) goto err;
|
||
|
||
rwconf->begin -= 1;
|
||
if (rwconf->begin < 0) rwconf->begin = 0;
|
||
if (rwconf->offset < 0) rwconf->offset = len;
|
||
|
||
for (i = 0; i < len; ++i, ++rules) {
|
||
if (count >= rwconf->begin + rwconf->offset) break;
|
||
if (**rules == ':') continue;
|
||
match = FAIL;
|
||
|
||
__chk_malloc(conf, struct ipt_config*, sizeof(*conf), ret, msg);
|
||
memset(conf, 0, sizeof(struct ipt_config));
|
||
|
||
if ((ret = __ipt_conf_parse(*rules, &(rwconf->conf), &match, conf)) != RET_OK) {
|
||
goto err;
|
||
}
|
||
if (match) {
|
||
if (count >= rwconf->begin) __ipt_config_tojson(root, conf);
|
||
count += 1;
|
||
}
|
||
|
||
xfree(conf);
|
||
}
|
||
|
||
out = cJSON_PrintUnformatted(root);
|
||
*outlen = strlen(out) + 1;
|
||
memcpy(output, out, *outlen);
|
||
|
||
MEMerr:
|
||
err:
|
||
xfree(conf);
|
||
xfree(rwconf);
|
||
xfree(out);
|
||
cJSON_Delete(root);
|
||
__free_dptr_char(&rules_start, len);
|
||
|
||
return ret;
|
||
}
|
||
|
||
ret_code get_nf_conntrack(const char * __restrict__ __filename,
|
||
char *output, int *outlen, char **msg) {
|
||
char **conntrack = NULL;
|
||
int len = 0, i;
|
||
char* out = NULL;
|
||
free_space = MAX_ERR_MSG;
|
||
ret_code ret = RET_OK;
|
||
|
||
//__chk_malloc((*msg), char*, free_space, ret, msg);
|
||
memset(*msg, 0, sizeof(char)*free_space);
|
||
|
||
conntrack = __read_nf_conntrack(__filename, &len, &ret, msg);
|
||
// TO DO
|
||
|
||
MEMerr:
|
||
return ret;
|
||
}
|
||
|
||
ret_code nat_config_recovery(char **msg) {
|
||
FILE *fp = NULL;
|
||
free_space = MAX_ERR_MSG;
|
||
ret_code ret = RET_OK;
|
||
|
||
__chk_malloc((*msg), char*, sizeof(char) * free_space, ret, NULL);
|
||
memset(*msg, 0, sizeof(char) * free_space);
|
||
|
||
fp = fopen("./iptables-conf.txt", "r");
|
||
if (fp != NULL) {
|
||
fclose(fp);
|
||
ret = run_command("sudo iptables-restore ./iptables-conf.txt 2>&1", msg);
|
||
}
|
||
|
||
MEMerr:
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* 原始调试程序,待修改,暂不可使用
|
||
*/
|
||
#ifdef NAT_DEBUG
|
||
int main(int argc, char *argv[]) {
|
||
int len;
|
||
char *out = NULL;
|
||
|
||
// 返回错误信息
|
||
char *err1 = NULL, *err2 = NULL;
|
||
|
||
//out = get_iptables_config(__iptables_conf_dir, &err1);
|
||
|
||
printf("%s\n", out);
|
||
printf("%s", err1);
|
||
|
||
__chk_free(out);
|
||
|
||
//set_iptables_config(__json, &err2);
|
||
printf("%s", err2);
|
||
|
||
free(err1);
|
||
free(err2);
|
||
return 0;
|
||
}
|
||
#endif
|
||
|