secgateway/Platform/user/configm/config-server/nat_config/config.c

1390 lines
40 KiB
C
Raw Normal View History

//
// 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: strint
*/
#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_handlergoto 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(&reg, pattern, REG_EXTENDED|REG_NEWLINE);
//执行正则表达式和缓存的比较
status=regexec(&reg, buf, nmatch, pmatch, 0);
regfree(&reg);
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