├── LICENSE ├── README.md ├── ip_core.c ├── ip_core.h └── test.c /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 shcabin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ipip-c 2 | IP数据库解析代码 支持dat和datx格式 (https://www.ipip.net/) 3 | 4 | ```shell 5 | gcc ip_core.c test.c -O2 -g -D benchmark 6 | ./a.out datx ../17monipdb.datx 7 | ./a.out dat ../17monipdb.dat 8 | ``` 9 | 10 | 基本用法: 11 | ```C 12 | ipip_t * hip=ip_init(type,path); //初始化 type=0 为dat格式 type=1为datx格式 13 | ip_find(hip,"8.8.8.8",buffer,sizeof(buffer));//查找单个ip 14 | ip_find_u(hip,3395848193,buffer,sizeof(buffer));//主机顺序整形ip 查找 15 | ip_uninit(hip);//反初始化 16 | ``` 17 | 性能: 18 | ``` 19 | dat 格式 500万次随机ip查询 1569毫秒 20 | datx 格式 500万次随机ip查询 293毫秒 21 | 机器 i7-3770 CPU @ 3.40GHz CentOS 7.1 22 | ``` 23 | -------------------------------------------------------------------------------- /ip_core.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "ip_core.h" 10 | 11 | struct ipip_s 12 | { 13 | unsigned char *buffer; 14 | unsigned char *data; 15 | unsigned char * offset; 16 | unsigned int buffer_len; 17 | unsigned int index; 18 | unsigned char *last_boundary; 19 | int (*ip_find)(ipip_t *h,char *,char *,int); 20 | int (*ip_find_u)(ipip_t *h,unsigned int ,char *,int); 21 | void (*ip_dump)(ipip_t *h); 22 | }; 23 | ipip_t * ip_init(int type,char *path); //type 0=dat 1=datx 24 | void ip_dat_dump(ipip_t *h); 25 | void ip_datx_dump(ipip_t *h); 26 | int ip_dat_find(ipip_t *h,char* str_ip,char *output,int output_len); 27 | int ip_datx_find(ipip_t *h,char* str_ip,char *output,int output_len); 28 | int ip_dat_find_u(ipip_t *h,unsigned int uip,char *output,int output_len); 29 | int ip_datx_find_u(ipip_t *h,unsigned int uip,char *output,int output_len); 30 | 31 | ipip_t *ip_init(int type,char *path) 32 | { 33 | struct ipip_s *ipip_info=0; 34 | struct stat st; 35 | unsigned long filesize = -1; 36 | fprintf(stderr,"enter ip_init %s\n",path); 37 | if((type!=0)&&(type!=1)) 38 | { 39 | fprintf(stderr,"type error\n"); 40 | return 0; 41 | } 42 | if (stat(path, &st) == -1) 43 | { 44 | fprintf(stderr,"stat error:%s\n",strerror(errno)); 45 | return 0; 46 | } 47 | filesize=st.st_size; 48 | if(filesize>20*1024*1024) 49 | { 50 | fprintf(stderr,"File too large\n"); 51 | return 0 ; 52 | } 53 | if(filesize<4) 54 | {//is a joke? 55 | fprintf(stderr,"File too small\n"); 56 | return 0 ; 57 | } 58 | int fd=open(path,O_RDONLY); 59 | if(fd<=0) 60 | { 61 | fprintf(stderr,"open file error:%s\n",strerror(errno)); 62 | return 0; 63 | } 64 | unsigned char *buffer=(unsigned char *)malloc(filesize); 65 | if(buffer==NULL) 66 | { 67 | return 0; 68 | } 69 | ssize_t nread=read(fd,buffer,filesize); 70 | if(nreadfilesize) 79 | { 80 | fprintf(stderr,"File error\n"); 81 | free(buffer); 82 | return 0; //文件不完整 83 | } 84 | ipip_info=calloc(sizeof(struct ipip_s),1); 85 | if(ipip_info==NULL) 86 | { 87 | free(buffer); 88 | return 0; 89 | } 90 | ipip_info->buffer=buffer; 91 | ipip_info->buffer_len=filesize; 92 | ipip_info->offset=buffer+index_len; 93 | ipip_info->last_boundary=buffer+filesize; 94 | 95 | char temp[16]; 96 | if(type==0) 97 | { 98 | ipip_info->ip_find=ip_dat_find; 99 | ipip_info->ip_find_u=ip_dat_find_u; 100 | ipip_info->ip_dump=ip_dat_dump; 101 | } 102 | else 103 | { 104 | ipip_info->ip_find=ip_datx_find; 105 | ipip_info->ip_find_u=ip_datx_find_u; 106 | ipip_info->ip_dump=ip_datx_dump; 107 | } 108 | if(ipip_info->ip_find(ipip_info,"255.255.255.255",temp,sizeof(temp))<0) 109 | { 110 | fprintf(stderr,"File error\n"); 111 | free(ipip_info); 112 | free(buffer); 113 | return 0; //文件不完整 114 | } 115 | return ipip_info; 116 | } 117 | void ip_uninit(ipip_t *hip) 118 | { 119 | if(hip) 120 | { 121 | free(hip->buffer); 122 | free(hip); 123 | } 124 | } 125 | void inline ip_dump(ipip_t *h) 126 | { 127 | return h->ip_dump(h); 128 | } 129 | int inline ip_find(ipip_t *h,char* str_ip,char *output,int output_len) 130 | { 131 | return h->ip_find(h,str_ip,output,output_len); 132 | } 133 | int inline ip_find_u(ipip_t *h,unsigned int uip,char *output,int output_len) 134 | { 135 | return h->ip_find_u(h,uip,output,output_len); 136 | } 137 | 138 | void ip_dat_dump(ipip_t *h) 139 | { 140 | ;//not implemented 141 | } 142 | 143 | int ip_dat_find_u(ipip_t *h,unsigned int uip,char *output,int output_len) 144 | { 145 | unsigned char * fip_pos = h->buffer + 4 + (uip>>24)*4; 146 | int start = (fip_pos[3]<<24)+ 147 | (fip_pos[2]<<16)+ 148 | (fip_pos[1]<<8)+ 149 | fip_pos[0]; //start 150 | unsigned char *start_pos=h->buffer+1028; 151 | unsigned char *end_pos = h->offset-1028; 152 | unsigned int index_offset = 0 , index_length = 0; 153 | for (start_pos=start_pos+start*8; start_pos= uip) 159 | { 160 | index_offset=(start_pos[6]<<16)+ 161 | (start_pos[5]<<8)+ 162 | start_pos[4]; 163 | index_length=start_pos[7]; 164 | unsigned char *res_offset = h->offset + index_offset - 1024; 165 | int len=index_length<(output_len-1)?index_length:(output_len-1); 166 | memcpy(output,res_offset,len); 167 | output[len]='\0'; 168 | break; 169 | } 170 | } 171 | return 0; 172 | } 173 | 174 | int ip_dat_find(ipip_t *h,char* str_ip,char *output,int output_len) 175 | { 176 | struct sockaddr_in sockaddr={0}; 177 | if(output_len<=0) 178 | { 179 | return 0; 180 | } 181 | if(inet_aton(str_ip, &sockaddr.sin_addr) == 0) 182 | { 183 | memset(output,'\t',output_len-1); 184 | output[output_len-1]=0; 185 | return 0; 186 | } 187 | unsigned int uip = ntohl(sockaddr.sin_addr.s_addr); 188 | return ip_dat_find_u(h,uip,output,output_len); 189 | } 190 | 191 | void ip_datx_dump(ipip_t *h) 192 | { 193 | ;//not implemented 194 | } 195 | int ip_datx_find_u(ipip_t *h,unsigned int uip,char *output,int output_len) 196 | { 197 | unsigned char * fip_pos = h->buffer + 4 + (uip>>16)*4; 198 | int start = (fip_pos[3]<<24)+(fip_pos[2]<<16)+ 199 | (fip_pos[1]<<8)+fip_pos[0]; //start 200 | unsigned char *start_pos=h->buffer+256*1024+4; //9+262144 201 | unsigned char *end_pos = h->offset-256*1024-4; 202 | int index_offset = 0 , index_length = 0; 203 | for (start_pos=start_pos+start*9; start_pos= uip) 209 | { 210 | index_offset=(start_pos[6]<<16)+ 211 | (start_pos[5]<<8)+ 212 | start_pos[4]; 213 | index_length=(start_pos[7]<<8)+start_pos[8]; 214 | unsigned char *res_offset = h->offset + index_offset - 262144; 215 | if(res_offset+index_length>h->last_boundary) 216 | { 217 | fprintf(stderr,"error last_boundary=%d\n",index_offset); 218 | memset(output,'\t',output_len-1); 219 | output[output_len-1]=0; 220 | return -1; 221 | } 222 | int len=index_length<(output_len-1)?index_length:(output_len-1); 223 | memcpy(output,res_offset,len); 224 | output[len]=0; 225 | break; 226 | } 227 | } 228 | return 0; 229 | } 230 | 231 | int ip_datx_find(ipip_t *h,char* str_ip,char *output,int output_len) 232 | { 233 | struct sockaddr_in sockaddr={0}; 234 | if(output_len<=0) 235 | { 236 | return -1; 237 | } 238 | if(inet_aton(str_ip, &sockaddr.sin_addr) == 0) 239 | { 240 | memset(output,'\t',output_len-1); 241 | output[output_len-1]=0; 242 | return -1; 243 | } 244 | unsigned int uip = ntohl(sockaddr.sin_addr.s_addr); 245 | return ip_datx_find_u(h,uip,output,output_len); 246 | } 247 | -------------------------------------------------------------------------------- /ip_core.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __IP_CORE_H__ 3 | #define __IP_CORE_H__ 4 | typedef struct ipip_s ipip_t; 5 | 6 | ipip_t * ip_init(int type,char *path); //type 0=dat 1=datx 7 | void ip_uninit(ipip_t *hip); 8 | int ip_find(ipip_t *h,char* str_ip,char *output,int output_len); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "ip_core.h" 11 | int main(int argc,char *argv[]) 12 | { 13 | ipip_t *hip; 14 | int type=-1; 15 | char buffer[256]; 16 | int k; 17 | if(argc==3) 18 | { 19 | if( (strcmp(argv[1],"dat")==0) ) 20 | { 21 | type=0; 22 | } 23 | else if(strcmp(argv[1],"datx")==0 ) 24 | { 25 | type=1; 26 | } 27 | else 28 | { 29 | fprintf(stderr,"param error,usage: exec dat|datx path\n"); 30 | return -1; 31 | } 32 | hip=ip_init(type,argv[2]); 33 | } 34 | else 35 | { 36 | hip=ip_init(0,"./17monipdb.dat"); 37 | } 38 | if(hip==NULL) 39 | { 40 | fprintf(stderr,"usage: exec dat|datx path\n"); 41 | return -1; 42 | } 43 | 44 | ip_find(hip,"203.208.62.0",buffer,sizeof(buffer)); 45 | printf("info:%s\n",buffer); 46 | ip_find(hip,"203.208.62.1",buffer,sizeof(buffer)); 47 | printf("info:%s\n",buffer); 48 | ip_find(hip,"209.85.228.223",buffer,sizeof(buffer)); 49 | printf("info:%s\n",buffer); 50 | ip_find_u(hip,202*256*256*256+104*256*256+136*256+197,buffer,sizeof(buffer)); 51 | printf("info:%s\n",buffer); 52 | ip_find(hip,"12.33.3.1",buffer,sizeof(buffer)); 53 | printf("info:%s\n",buffer); 54 | 55 | #ifdef benchmark 56 | struct timeval tpstart,tpend; 57 | float timeuse; 58 | gettimeofday(&tpstart,NULL); 59 | unsigned int uip; 60 | for(k=0;k<10000*100;k++) 61 | { 62 | #if 0 63 | ip_find(hip,"8.8.8.8",buffer,sizeof(buffer)); 64 | ip_find(hip,"192.168.0.1",buffer,sizeof(buffer)); 65 | ip_find(hip,"255.255.255.255",buffer,sizeof(buffer)); 66 | 67 | ip_find(hip,"1.2.3.4",buffer,sizeof(buffer)); 68 | ip_find(hip,"111.222.333.444",buffer,sizeof(buffer)); 69 | #else 70 | uip=rand()<<2; 71 | ip_find_u(hip,uip,buffer,sizeof(buffer)); 72 | uip=rand()<<2; 73 | ip_find_u(hip,uip,buffer,sizeof(buffer)); 74 | uip=rand()<<2; 75 | ip_find_u(hip,uip,buffer,sizeof(buffer)); 76 | uip=rand()<<2; 77 | ip_find_u(hip,uip,buffer,sizeof(buffer)); 78 | uip=rand()<<2; 79 | ip_find_u(hip,uip,buffer,sizeof(buffer)); 80 | #endif 81 | } 82 | gettimeofday(&tpend,NULL); 83 | timeuse=1000*(tpend.tv_sec-tpstart.tv_sec)+ (tpend.tv_usec-tpstart.tv_usec)/1000; 84 | printf("used uime:%f(ms)\n",timeuse); 85 | #endif 86 | ip_uninit(hip); 87 | return 0; 88 | } 89 | 90 | --------------------------------------------------------------------------------