469 lines
9.8 KiB
C
469 lines
9.8 KiB
C
#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"
|
||
|
||
|
||
|
||
struct rpdb_mark {
|
||
struct list_head list;
|
||
union {
|
||
struct in6_addr ip6;
|
||
struct in_addr ip4;
|
||
|
||
}ip;
|
||
|
||
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}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$"
|
||
|
||
#define RPDP_MARK_HASH_DEPTH (1024)
|
||
static int gRpdbMark = 0;
|
||
|
||
/*
|
||
* mark hash list,save mark
|
||
*/
|
||
struct list_head gRpdbMarkList[RPDP_MARK_HASH_DEPTH] = {0};
|
||
|
||
|
||
/*
|
||
popen
|
||
*/
|
||
|
||
|
||
void
|
||
print_result(FILE *fp)
|
||
{
|
||
char buf[100];
|
||
|
||
if(!fp) {
|
||
return;
|
||
}
|
||
printf("\n>>>\n");
|
||
memset(buf, 0, sizeof(buf));
|
||
fgets(buf, sizeof(buf) - 1, fp) ;
|
||
|
||
|
||
printf("%s", buf);
|
||
|
||
|
||
printf("\n<<<\n");
|
||
}
|
||
|
||
int rpdb_popen(char *cmd)
|
||
{
|
||
FILE *fp = NULL;
|
||
|
||
|
||
fp = NULL;
|
||
fp = popen(cmd, "r");
|
||
if(!fp)
|
||
{
|
||
perror("popen");
|
||
exit(EXIT_FAILURE);
|
||
}
|
||
print_result(fp);
|
||
pclose(fp);
|
||
sleep(1);
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* rpdb 初始化接口
|
||
*/
|
||
bool rpdb_init_route()
|
||
{
|
||
FILE *fp = NULL;
|
||
int i = 0;
|
||
|
||
system("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);
|
||
|
||
|
||
/*
|
||
初始化链表
|
||
*/
|
||
for (i = 0; i < RPDP_MARK_HASH_DEPTH; i++)
|
||
{
|
||
INIT_LIST_HEAD(&gRpdbMarkList[i]);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
|
||
static int gRpdbTableIndex = 1; /* 1 - 252 */
|
||
#define RPDB_TABLE_ADD (0)
|
||
#define RPDB_TABLE_DEL (1)
|
||
bool rpdb_add_delete_table(const char* gateway,const char *tbl_name,int op)
|
||
{
|
||
char table_name[128] = {0};
|
||
char line_cnt[1024] = {0};
|
||
FILE *fp = NULL;
|
||
FILE *fp_tmp = NULL;
|
||
bool ret = false;
|
||
int i = 0;
|
||
int cn_num = 0;
|
||
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 false;
|
||
}
|
||
}
|
||
|
||
fp = fopen(RT_TABLES_PATH,"ra+");
|
||
if (NULL == fp)
|
||
{
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
while(!feof(fp)) /* 遍历文件每一行,查找 路由表是否存在 */
|
||
{
|
||
memset(line_cnt,0,1024);
|
||
fgets(line_cnt,1024,fp);
|
||
if(strstr(line_cnt,table_name))
|
||
{
|
||
if (op == RPDB_TABLE_ADD)
|
||
{
|
||
fclose(fp);
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
向文件最后一行添加 路由表项
|
||
*/
|
||
if (op == RPDB_TABLE_ADD)
|
||
{
|
||
if (gRpdbTableIndex > 252)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
memset(line_cnt,0,1024);
|
||
sprintf(line_cnt,"%d %s",gRpdbTableIndex,table_name);
|
||
printf("RPDB_TABLE_ADD:%s\n",line_cnt);
|
||
fprintf(fp,"%s\n",line_cnt);
|
||
fclose(fp);
|
||
gRpdbTableIndex++;
|
||
return true;
|
||
}
|
||
|
||
if (op == RPDB_TABLE_DEL)
|
||
{
|
||
fp = fopen(RT_TABLES_PATH,"r+");
|
||
if (NULL == fp)
|
||
{
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
fp_tmp = fopen("/tmp/rt_tables","w");
|
||
if (fp_tmp == NULL) return false;
|
||
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 true;
|
||
}
|
||
|
||
/*
|
||
* 判断ip地址是否合法
|
||
*/
|
||
|
||
int rpdb_ipaddr_match(char *ip_addr,int flag)
|
||
{
|
||
regex_t reg;
|
||
regmatch_t match[1];
|
||
int retval = 0;
|
||
|
||
if (flag == 1)
|
||
{
|
||
retval = regcomp(®, IPV4_PATTERN, REG_EXTENDED | REG_NEWLINE);
|
||
}
|
||
else
|
||
{
|
||
retval = regcomp(®, IPV6_PATTERN, REG_EXTENDED | REG_NEWLINE);
|
||
}
|
||
|
||
retval = regexec(®,ip_addr, sizeof match / sizeof match[0], match, 0);
|
||
printf("%s is %s\n", ip_addr, retval == 0 ? "legal" : "illegal");
|
||
regfree(®);
|
||
return retval;
|
||
}
|
||
|
||
|
||
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)
|
||
{
|
||
if (node1.ip.ip4.s_addr == node2.ip.ip4.s_addr)
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
* 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(const char* gateway)
|
||
{
|
||
in_addr_t addr;
|
||
if (NULL == gateway)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
addr = inet_addr(gateway);
|
||
struct rpdb_mark node;
|
||
node.ip.ip4.s_addr = addr;
|
||
return rpdb_mark_hash_add(node);
|
||
}
|
||
|
||
/*
|
||
* 路由添加接口
|
||
*/
|
||
bool rpdb_add_route(const char* gateway,const char *tbl_name)
|
||
{
|
||
char cmd[256] = {0};
|
||
int status = 0;
|
||
char table_name[128] = {0};
|
||
int mark = 0;
|
||
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 false;
|
||
}
|
||
}
|
||
|
||
if (rpdb_add_delete_table(gateway,tbl_name,RPDB_TABLE_ADD) == false)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (strstr(":",gateway))
|
||
{
|
||
sprintf(cmd,"ip -6 route add default via %s table %s",gateway,table_name);
|
||
}
|
||
else
|
||
{
|
||
sprintf(cmd,"ip route add default via %s table %s",gateway,table_name);
|
||
}
|
||
|
||
printf("%s\n",cmd);
|
||
rpdb_popen(cmd);
|
||
|
||
mark = rpdb_gen_mark(gateway);
|
||
memset(cmd,0,sizeof(cmd));
|
||
sprintf(cmd,"ip rule add fwmark %d table %s",mark,table_name);
|
||
printf("%s\n",cmd);
|
||
rpdb_popen(cmd);
|
||
|
||
return 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);
|
||
//ipaddr_match("fe80:0000:0000:0000:0204:61ff:fe9d:ffffff15",2);
|
||
struct rpdb_mark mark_value;
|
||
struct rpdb_mark mark_value1;
|
||
in_addr_t addr;
|
||
rpdb_init_route();
|
||
rpdb_add_delete_table("1.1.2.1",NULL,RPDB_TABLE_ADD);
|
||
rpdb_add_delete_table("1.1.2.1",NULL,RPDB_TABLE_ADD);
|
||
rpdb_add_delete_table("1.2.2.1",NULL,RPDB_TABLE_ADD);
|
||
rpdb_add_delete_table("2.1.2.1",NULL,RPDB_TABLE_ADD);
|
||
|
||
rpdb_add_delete_table("2.1.2.1",NULL,RPDB_TABLE_DEL);
|
||
//rpdb_add_delete_table("2.1.2.1",NULL,RPDB_TABLE_DEL);
|
||
//rpdb_add_delete_table("1.1.2.1",NULL,RPDB_TABLE_DEL);
|
||
addr = inet_addr("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);
|
||
|
||
|
||
|
||
rpdb_add_route("1.2.3.3",NULL);
|
||
rpdb_add_route("2.2.4.3",NULL);
|
||
rpdb_add_route("3.2.4.3",NULL);
|
||
rpdb_add_route("4.2.4.3",NULL);
|
||
|
||
return 0;
|
||
}
|