#include #include #include #include #include #include #include #include #include #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 list,save 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 = NULL; 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(®, IPV4_PATTERN, REG_EXTENDED | REG_NEWLINE); } else if(flag == IPV6_ADDR) { retval = regcomp(®, IPV6_PATTERN, REG_EXTENDED | REG_NEWLINE); } else { return -1; } retval = regexec(®,ip_addr, sizeof match / sizeof match[0], match, 0); printf("%s is %s\n", ip_addr, retval == 0 ? "legal" : "illegal"); regfree(®); 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) 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) { return -1; } if(index > 1) { rpdb_calc(table_name,RPDB_ROUTE_DEL); return mark; } fp = fopen(RT_TABLES_PATH,"r+"); if (NULL == fp) { return -1; } else { fp_tmp = fopen("/tmp/rt_tables","w"); if (fp_tmp == NULL) 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; } } } } /* * 路由添加接口 */ 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