secgateway/Platform/user/rpdb/rpdb.c

793 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <regex.h>
#include "list.h"
#include "rpdb.h"
#if 0
rm -fr /tmp/nf_conntrack*
cp -fr /proc/net/nf_conntrack /tmp/nf_conntrack
cat /tmp/nf_conntrack |awk -F ' ' '{print $4}'|xargs -I {} echo {} >> /tmp/nf_conntrack_proto;
cat /tmp/nf_conntrack |awk -F ' ' '{print $7}' | awk -F '=' '{print $2}' |xargs -I {} echo {} >> /tmp/nf_conntrack_dip;
cat /tmp/nf_conntrack |awk -F ' ' '{print $9}' | awk -F '=' '{print $2}' |xargs -I {} echo {} >> /tmp/nf_conntrack_dport;
paste /tmp/nf_conntrack_proto /tmp/nf_conntrack_dip /tmp/nf_conntrack_dport | xargs -I {} echo {} >>/tmp/dpi_triple1;
sort -k2n /tmp/dpi_triple1 | uniq > /tmp/dpi_triple
#endif
struct rpdb_mark {
struct list_head list;
union {
struct in6_addr ip6;
struct in_addr ip4;
}ip;
bool ipv4;
int mark;
};
char rt_table[11][128]= {
"# reserved values",
"#",
"255 local",
"254 main",
"253 default",
"0 unspe",
"#",
"# local",
"#",
"#1 inr.ruhep"
};
#define RT_TABLES_PATH ("/etc/iproute2/rt_tables")
#define IPV4_PATTERN "^([0-9]|[1-9][0-9]|1[0-9]{1,2}|2[0-4][0-9]|25[0-5]).([0-9]|[1-9][0-9]|1[0-9]{1,2}|2[0-4][0-9]|25[0-5]).([0-9]|[1-9][0-9]|1[0-9]{1,2}|2[0-4][0-9]|25[0-5]).([0-9]|[1-9][0-9]|1[0-9]{1,2}|2[0-4][0-9]|25[0-5])$"
#define IPV6_PATTERN "^\s*((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4}){0,4}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))(%.+)?\s*$"
#define RPDP_MARK_HASH_DEPTH (1024)
static int gRpdbMark = 0;
/*
* mark hash listsave mark
*/
static struct list_head gRpdbMarkList[RPDP_MARK_HASH_DEPTH] = {0};
static int gRpdbTableIndex = 1; /* 1 - 252 */
static pthread_mutex_t mutex;
#define IPV4_ADDR (1)
#define IPV6_ADDR (2)
struct rpdb_stat{
char table_name[256];
int index;
};
struct rpdb_stat rpdbstat[256] = {0};
/*
popen
*/
void print_result(FILE *fp)
{
char buf[100];
if(!fp)
{
return;
}
memset(buf, 0, sizeof(buf));
fgets(buf, sizeof(buf) - 1, fp);
printf("%s", buf);
return;
}
int rpdb_popen(char *cmd)
{
FILE *fp = popen(cmd, "r");
if(!fp)
{
perror("popen");
exit(EXIT_FAILURE);
}
print_result(fp);
pclose(fp);
return 0;
}
int rpdb_system(char *cmd)
{
return system(cmd);
}
/*
* rpdb 初始化接口
*/
bool rpdb_init_route()
{
FILE *fp = NULL;
int i = 0;
char cmd[256] = {0};
/*
初始化多路由表
*/
rpdb_popen("echo > /etc/iproute2/rt_tables");
fp = fopen(RT_TABLES_PATH,"w");
if (fp)
{
for (i = 0; i < 11; i++)
{
fprintf(fp,"%s\n",rt_table[i]);
}
}
else
{
return false;
}
fclose(fp);
/*
初始化策略路由规则ip rule
*/
memset(cmd,0,sizeof(cmd));
sprintf(cmd,"%s","ip rule|grep fwmark|awk -F ' ' '{print $7}'|xargs -I {} ip rule del table {}");
rpdb_system(cmd);
/*
flush 路由
*/
memset(cmd,0,sizeof(cmd));
sprintf(cmd,"%s","ip route flush cache");
rpdb_system(cmd);
/*
初始化链表
*/
for (i = 0; i < RPDP_MARK_HASH_DEPTH; i++)
{
INIT_LIST_HEAD(&gRpdbMarkList[i]);
}
memset((char*)&rpdbstat,0,256*sizeof(struct rpdb_stat));
pthread_mutex_init(&mutex, NULL);
return true;
}
int rpdb_calc(char *name,int flag)
{
int i = 0;
int j = 0;
int flag1 = 0;
/*
路由表存在,只修改路由表对应的策略数
*/
for (i = 0; i < 256; i++)
{
if (strcmp(name,rpdbstat[i].table_name) == 0)
{
if (flag == RPDB_ROUTE_ADD)
{
rpdbstat[i].index++;
}
else if(flag == RPDB_ROUTE_DEL)
{
rpdbstat[i].index--;
}
if(rpdbstat[i].index == 0)
memset(rpdbstat[i].table_name,0,sizeof(rpdbstat[i].table_name));
flag1 = 1;
break;
}
}
/*
路由表不存在添加路由表name并赋值策略数
*/
if (flag1 == 0)
{
for (j = 0; j < 256; j++)
{
if (flag == RPDB_ROUTE_ADD)
{
if(!rpdbstat[j].table_name[0])
{
strcpy(rpdbstat[j].table_name,name);
rpdbstat[j].index = 1;
//printf("%s,%d,index:%d,%s\n",__FUNCTION__,__LINE__,rpdbstat[j].index,rpdbstat[j].table_name);
return rpdbstat[j].index;
}
}
}
}
}
int rpdb_get_index(char* name)
{
int i = 0;
for (i = 0; i < 256; i++)
{
if (strcmp(name,rpdbstat[i].table_name) == 0)
{
return rpdbstat[i].index;
}
}
return 0;
}
#if 0
inet_pton(AF_INET6, "2a01:198:603:0:396e:4789:8e99:890f", &ip);
printf("0x%x%x%x%x\n", htonl(ip.s6_addr32[0]),htonl(ip.s6_addr32[1]),htonl(ip.s6_addr32[2]),htonl(ip.s6_addr32[3]));
inet_pton(AF_INET6, "2a01:198:603:0::", &ip);
printf("0x%x%x%x%x\n", htonl(ip.s6_addr32[0]),htonl(ip.s6_addr32[1]),htonl(ip.s6_addr32[2]),htonl(ip.s6_addr32[3]));
#endif
int is_valid_ipv4(char *ipv4)
{
struct in_addr addr;
if(ipv4 == NULL)
return 0;
if(inet_pton(AF_INET, ipv4, (void *)&addr) == 1)
{
return 1;
}
return 0;
}
int is_valid_ipv6(char *ipv6)
{
struct in6_addr addr6;
if(ipv6 == NULL)
return 0;
if(inet_pton(AF_INET6, ipv6, (void *)&addr6) == 1)
{
return 1;
}
return 0;
}
/*
* 判断ip地址是否合法
*/
#if 0
int rpdb_ipaddr_match(char *ip_addr,int flag)
{
regex_t reg;
regmatch_t match[1];
int retval = 0;
if (flag == IPV4_ADDR)
{
retval = regcomp(&reg, IPV4_PATTERN, REG_EXTENDED | REG_NEWLINE);
}
else if(flag == IPV6_ADDR)
{
retval = regcomp(&reg, IPV6_PATTERN, REG_EXTENDED | REG_NEWLINE);
}
else
{
return -1;
}
retval = regexec(&reg,ip_addr, sizeof match / sizeof match[0], match, 0);
printf("%s is %s\n", ip_addr, retval == 0 ? "legal" : "illegal");
regfree(&reg);
if (retval == 0)
return 1;
else
return 0;
}
#endif
/*
1 - 成功
0 - 失败
*/
int rpdb_ipaddr_match(char *ip_addr,int flag)
{
if (flag == IPV4_ADDR)
{
return is_valid_ipv4(ip_addr);
}
else if (flag == IPV6_ADDR)
{
return is_valid_ipv6(ip_addr);
}
return 0;
}
int rpdb_ip_hash(struct rpdb_mark node)
{
int ip_value = 0;
int hash = 0;
int i = 0;
if (node.ip.ip4.s_addr != 0 )
{
ip_value = node.ip.ip4.s_addr;
}
else
{
for (i = 0; i < 4; ++i)
{
ip_value += node.ip.ip6.s6_addr32[i];
}
}
hash = (ip_value&0xF) + ((ip_value >> 8)&0xF) + ((ip_value >> 16)&0xF) + ((ip_value >> 24)&0xF);
hash = hash&(1024-1);
return hash;
}
/*
* node比较
*/
bool rpdb_mark_node_compare(struct rpdb_mark node1,struct rpdb_mark node2)
{
int i = 0;
if (node1.ipv4 == true)
{
if (node1.ip.ip4.s_addr == node2.ip.ip4.s_addr)
{
return true;
}
else
{
return false;
}
}
else
{
for (i = 0; i < 4; i++){
if (node1.ip.ip6.s6_addr32[i] != node2.ip.ip6.s6_addr32[i]){
return false;
}
}
}
return true;
}
/*
* mark 查找,返回链上的node节点
*/
struct rpdb_mark * rpdb_mark_search(struct rpdb_mark node)
{
struct list_head * pList;
struct rpdb_mark *pNode;
int hash = rpdb_ip_hash(node);
list_for_each(pList,&gRpdbMarkList[hash]) {
pNode = list_entry(pList,struct rpdb_mark,list);
//printf("%s,%d,%d,%d\n",__FUNCTION__,__LINE__,pNode->ip.ip4.s_addr,pNode->mark);
if (rpdb_mark_node_compare(node,*pNode)){
//printf("%s,%d,mark = %d\n",__FUNCTION__,__LINE__,pNode->mark);
return pNode;
}
}
return NULL;
}
/*
* mark
*/
int rpdb_mark_hash_add(struct rpdb_mark node)
{
struct rpdb_mark *pNode = NULL;
int hash = 0;
pNode = rpdb_mark_search(node);
if (pNode != NULL)
{
return pNode->mark;
}
pNode = (struct rpdb_mark*)malloc(sizeof(struct rpdb_mark));
if (NULL == pNode)
{
return false;
}
hash = rpdb_ip_hash(node);
node.mark = ++gRpdbMark;
memcpy((char*)pNode,(char*)&node,sizeof(struct rpdb_mark));
//printf("%s,%d,%d,%d\n",__FUNCTION__,__LINE__,pNode->ip.ip4.s_addr,pNode->mark);
/*
节点添加到链尾部
*/
list_add_tail(&pNode->list,&gRpdbMarkList[hash]);
return gRpdbMark;
}
/*
* 根据下一跳地址生成mark
*/
int rpdb_gen_mark(char* gateway)
{
in_addr_t addr;
if (NULL == gateway)
{
return -1;
}
addr = inet_addr(gateway);
struct rpdb_mark node;
node.ipv4 = false;
if(rpdb_ipaddr_match(gateway,IPV4_ADDR) == 1)
{
node.ip.ip4.s_addr = addr;
node.ipv4 = true;
}
else if(rpdb_ipaddr_match(gateway,IPV6_ADDR) == 1)
{
inet_pton(AF_INET6, gateway, (void *)&node.ip.ip6);
node.ipv4 = false;
}
else
{
return -1;
}
return rpdb_mark_hash_add(node);
}
int rpdb_add_route(char *gateway,char *table_name)
{
char cmd[256] = {0};
char cmd1[256] = {0};
int ret = 0;
int mark = 0;
if(rpdb_ipaddr_match(gateway,IPV6_ADDR) == 1)
{
sprintf(cmd,"ip -6 route add default via %s table %s",gateway,table_name);
sprintf(cmd1,"ip -6 route del default via %s table %s",gateway,table_name);
}
else
{
sprintf(cmd,"ip route add default via %s table %s",gateway,table_name);
sprintf(cmd1,"ip route del default via %s table %s",gateway,table_name);
}
/*先删除之前可能存在的路由,否则添加路由可能会报错*/
rpdb_system(cmd1);
/*添加路由*/
ret = rpdb_system(cmd);
printf("%s,%d,ret=%d,%s\n",__FUNCTION__,__LINE__,ret,cmd);
if(ret != 0)
{
return -1;
}
mark = rpdb_gen_mark(gateway);
memset(cmd,0,sizeof(cmd));
sprintf(cmd,"ip rule add fwmark %d table %s",mark,table_name);
ret = rpdb_system(cmd);
if (ret != 0)
return -1;
/*
刷新路由
*/
memset(cmd,0,sizeof(cmd));
sprintf(cmd,"%s","ip route flush cache");
ret = rpdb_system(cmd);
if (ret != 0)
return -1;
printf("%s,%d,ret=%d,%s\n",__FUNCTION__,__LINE__,ret,cmd);
return 0;
}
int rpdb_del_route(char *gateway,char *table_name)
{
char cmd[256] = {0};
int ret = 0;
if (strstr(":",gateway))
{
sprintf(cmd,"ip -6 route del default via %s table %s",gateway,table_name);
}
else
{
sprintf(cmd,"ip route del default via %s table %s",gateway,table_name);
}
ret = rpdb_system(cmd);
if (ret != 0)
return -1;
memset(cmd,0,sizeof(cmd));
sprintf(cmd,"ip rule del table %s",table_name);
ret = rpdb_system(cmd);
if (ret != 0)
return -1;
/*
刷新路由
*/
memset(cmd,0,sizeof(cmd));
sprintf(cmd,"%s","ip route flush cache");
ret = rpdb_system(cmd);
if (ret != 0)
return -1;
printf("%s,%d,ret=%d,%s\n",__FUNCTION__,__LINE__,ret,cmd);
return 0;
}
/*
返回nexthop对应的策略数
*/
int rpdb_add_delete_table(char *gateway,char* tbl_name,int op)
{
char line_cnt[1024] = {0};
FILE *fp = NULL;
FILE *fp_tmp = NULL;
bool ret = false;
int i = 0;
int cn_num = 0;
int index = 0;
int mark = 0;
char table_name[256] = {0};
int flag = 0;
/*
判断ip地址是否合法
*/
if((rpdb_ipaddr_match(gateway,IPV6_ADDR) == 0)&&
(rpdb_ipaddr_match(gateway,IPV4_ADDR) == 0))
{
printf("ipv addr invalid:%s\n",gateway);
return -1;
}
/*
生成路由表名字
*/
if (tbl_name == NULL)
{
memset(table_name,0,sizeof(table_name));
sprintf(table_name,"table_%s",gateway);
}
else
{
if (strlen(tbl_name) > 1) /* 检查name的合法性*/
{
memset(table_name,0,sizeof(table_name));
sprintf(table_name,"%s",tbl_name);
}
else
{
return -1;
}
}
printf("tbl_name:%s\n",table_name);
mark = rpdb_gen_mark(gateway);
index = rpdb_get_index(table_name);
printf("%s,%d,index=%d\n",__FUNCTION__,__LINE__,index);
fp = fopen(RT_TABLES_PATH,"ra+");
if (NULL == fp)
{
return -1;
}
/*
向文件最后一行添加 路由表项
*/
if (op == RPDB_ROUTE_ADD)
{
while(!feof(fp)) /* 遍历文件每一行,查找 路由表是否存在 */
{
memset(line_cnt,0,1024);
fgets(line_cnt,1024,fp);
if(strstr(line_cnt,table_name))
{
rpdb_calc(table_name,RPDB_ROUTE_ADD);
fclose(fp);
return mark;
}
}
if (gRpdbTableIndex > 252)
{
return -1;
}
memset(line_cnt,0,1024);
sprintf(line_cnt,"%d %s",gRpdbTableIndex,table_name);
fprintf(fp,"%s\n",line_cnt);
fclose(fp);
gRpdbTableIndex++;
if(0 == rpdb_add_route(gateway,table_name))
{
rpdb_calc(table_name,RPDB_ROUTE_ADD);
return mark;
}
else
{
/*
删除路由表
*/
fp = fopen(RT_TABLES_PATH,"ra+");
if(NULL == fp) return -1;
fp_tmp = fopen("/tmp/rt_tables","w");
if (fp_tmp == NULL)
{
fclose(fp);
return -1;
}
while(!feof(fp)) /* 遍历文件每一行,查找 路由表是否存在 */
{
memset(line_cnt,0,1024);
fgets(line_cnt,1024,fp);
if(!strstr(line_cnt,table_name))
{
fprintf(fp_tmp,"%s",line_cnt);
}
}
fclose(fp);
fclose(fp_tmp);
system("cp -fr /tmp/rt_tables /etc/iproute2/rt_tables");
return -1;
}
}
if (op == RPDB_ROUTE_DEL)
{
if(index < 1)
{
fclose(fp);
return -1;
}
if(index > 1)
{
fclose(fp);
rpdb_calc(table_name,RPDB_ROUTE_DEL);
return mark;
}
if (NULL == fp)
{
return -1;
}
else
{
fp_tmp = fopen("/tmp/rt_tables","w");
if (fp_tmp == NULL)
{
fclose(fp);
return -1;
}
while(!feof(fp)) /* 遍历文件每一行,查找 路由表是否存在 */
{
memset(line_cnt,0,1024);
fgets(line_cnt,1024,fp);
if(!strstr(line_cnt,table_name))
{
fprintf(fp_tmp,"%s",line_cnt);
}
else
{
flag = 1;
/*
删除路由表之前先把路由删掉
*/
if(0 == rpdb_del_route(gateway,table_name))
{
rpdb_calc(table_name,RPDB_ROUTE_DEL);
}
}
}
fclose(fp);
fclose(fp_tmp);
system("cp -fr /tmp/rt_tables /etc/iproute2/rt_tables");
if (flag == 1)
{
return mark;
}
else
{
return -1;
}
}
}
fclose(fp);
return -1;
}
/*
* 路由添加接口
*/
int rpdb_add_del_route(char* gateway,char *tbl_name,int opt)
{
return rpdb_add_delete_table(gateway,tbl_name,opt);
}
#if 0
int main()
{
//ipaddr_match("192.168.1.1",1);
//ipaddr_match("192.168.1.300",1);
//ipaddr_match("2000:0:0:0:0:0:0:1 ",2);
rpdb_ipaddr_match("fe80:0000:0000:0000:0204:61ff:fe9d:f5",2);
struct rpdb_mark mark_value;
struct rpdb_mark mark_value1;
in_addr_t addr;
rpdb_init_route();
addr = inet_addr("table_2006.6.6.6");
mark_value.ip.ip4.s_addr = addr;
rpdb_mark_hash_add(mark_value);
rpdb_mark_hash_add(mark_value);
rpdb_mark_hash_add(mark_value);
rpdb_mark_hash_add(mark_value);
addr = inet_addr("7.7.7.7");
mark_value1.ip.ip4.s_addr = addr;
rpdb_mark_hash_add(mark_value1);
rpdb_mark_hash_add(mark_value1);
/*
192.168.221.2 为有效的下一跳网关地址,添加成功
*/
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2",NULL,RPDB_ROUTE_ADD));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2","test_table",RPDB_ROUTE_ADD));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2",NULL,RPDB_ROUTE_DEL));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2","test_table",RPDB_ROUTE_DEL));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2",NULL,RPDB_ROUTE_ADD));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2","test_table",RPDB_ROUTE_ADD));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2",NULL,RPDB_ROUTE_DEL));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2","test_table",RPDB_ROUTE_DEL));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2",NULL,RPDB_ROUTE_ADD));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2","test_table",RPDB_ROUTE_ADD));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2",NULL,RPDB_ROUTE_DEL));
printf("~~~~~~%d\n",rpdb_add_del_route("192.168.221.2","test_table",RPDB_ROUTE_DEL));
/*
错误的网关地址
*/
printf("~~~~~~%d\n",rpdb_add_del_route("172.168.221.2",NULL,RPDB_ROUTE_ADD));
printf("~~~~~~%d\n",rpdb_add_del_route("112.168.221.2",NULL,RPDB_ROUTE_ADD));
/*
非法IP地址
*/
printf("~~~~~~%d\n",rpdb_add_del_route("392.168.221.2",NULL,RPDB_ROUTE_ADD));
printf("~~~~~~%d\n",rpdb_add_del_route("2a01:198:603:0:396e:4789:8e99:890f",NULL,RPDB_ROUTE_ADD));
return 0;
}
#endif