qqwry

本文介绍了一个基于QQWRY IP定位库的C语言实现,该程序能够将IP地址转换为对应的地理位置信息,包括国家和地区。通过二进制搜索算法快速定位到IP所属区域,并解析出详细的地理位置数据。

/*
 * Copyright 2008,2009 Surf Chen <http://www.surfchen.org>
 *
 *
 * This source code is under the terms of the
 * GNU Lesser General Public License.
 * see <http://www.gnu.org/licenses/lgpl.txt>
 */

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#define BE_32(x) ((((uint8_t*)(x))[0]<<24) |/
                  (((uint8_t*)(x))[1]<<16) |/
                  (((uint8_t*)(x))[2]<<8) |/
                  ((uint8_t*)(x))[3])

#define LE_32(x) ((((uint8_t*)(x))[3]<<24) |/
                  (((uint8_t*)(x))[2]<<16) |/
                  (((uint8_t*)(x))[1]<<8) |/
                  ((uint8_t*)(x))[0])

#define LE_24(x) ((((uint8_t*)(x))[2]<<16) |/
                  (((uint8_t*)(x))[1]<<8) |/
                  ((uint8_t*)(x))[0])

#define REDIRECT_TYPE_1 0x01
#define REDIRECT_TYPE_2 0x02
           
static uint32_t ip2long(const char *ip) {
    uint32_t ip_long=0;
    uint8_t ip_len=strlen(ip);
    uint32_t ip_sec=0;
    int8_t ip_level=3;
    uint8_t i,n;
    for (i=0;i<=ip_len;i++) {
        if (i!=ip_len && ip[i]!='.' && ip[i]<48 || ip[i]>57) {
            continue;
        }
        if (ip[i]=='.' || i==ip_len) {
            /*too many .*/
            if (ip_level==-1) {
                return 0;
            }
            for (n=0;n<ip_level;n++) {
                ip_sec*=256;
            }
            ip_long+=ip_sec;
            if (i==ip_len) {
                break;
            }
            ip_level--;
            ip_sec=0;
        } else {
            /*char '0' == int 48*/
            ip_sec=ip_sec*10+(ip[i]-48);
        }
    }
    return ip_long;
}
static uint32_t search_index(const uint32_t ip,FILE *qqwry_file) {
    uint32_t index_ip;
    unsigned char head[8];
    unsigned char index_bytes[7];
    fread(head,8,1,qqwry_file);
    uint32_t index_start,index_end,index_mid;
    index_start = (uint32_t)LE_32(&head[0]);
    index_end = (uint32_t)LE_32(&head[4]);
    while (1) {
        if ((index_end-index_start)==7) {
            break;
        }
        //printf("index:%u:%u/n",index_start,index_end);
        index_mid=index_end/7 - index_start/7;
        if (index_mid%2==0) {
            index_mid=index_mid/2;
        } else {
            index_mid=(index_mid+1)/2;
        }
        index_mid=index_start+index_mid*7;
        fseek(qqwry_file,index_mid,SEEK_SET);
        fread(index_bytes,7,1,qqwry_file);
        index_ip=(uint32_t)LE_32(&index_bytes[0]);
        if (index_ip==ip) {
            break;
        } else if (index_ip<ip) {
            index_start=index_mid;
        } else {
            index_end=index_mid;
        }
    }
    if (index_ip>ip) {
        fseek(qqwry_file,index_start,SEEK_SET);
        fread(index_bytes,7,1,qqwry_file);
    }
    return (uint32_t)LE_24(&index_bytes[4]);
}
static int readOrJumpRead(char *location,FILE *qqwry_file,const uint32_t data_index) {
    unsigned char c;
    unsigned char data_index_bytes[3];
    uint32_t jump_data_index=0;
    if (data_index) {
        fseek(qqwry_file,data_index,SEEK_SET);
    }
    c=fgetc(qqwry_file);
    switch (c) {
        case REDIRECT_TYPE_2:
        case REDIRECT_TYPE_1:
            fread(data_index_bytes,3,1,qqwry_file);
            jump_data_index=LE_24(&data_index_bytes[0]);
            fseek(qqwry_file,jump_data_index,SEEK_SET);
            break;
        default:
            location[strlen(location)]=c;
    }
    if (c) {
        while (c=fgetc(qqwry_file)) {
            location[strlen(location)]=c;
        }
    }
    return 1;
}
static int is_cz88(const char *str) {
    int i;
    int l=strlen(str)-7;
    for (i=0;i<l;i++) {
        if (str[i]=='C'
            && str[i+1]=='Z'
            && str[i+2]=='8'
            && str[i+3]=='8'
            && str[i+4]=='.'
            && str[i+5]=='N'
            && str[i+6]=='E'
            && str[i+7]=='T'
        ) {
            return 1;
        }
    }
    return 0;
}
int qqwry_get_location_by_long(char *addr1,char *addr2,const uint32_t ip,FILE *qqwry_file) {
    //printf("%u",ip);
    unsigned char data_index_bytes[3];
    uint32_t data_index;
    uint32_t addr2_offset;
    unsigned char c;

    if (!qqwry_file) {
        return 0;
    }
    fseek(qqwry_file,0,SEEK_SET);
    data_index = search_index(ip,qqwry_file);
    //fprintf(stderr,"index:%u:%u/n",ftell(qqwry_file),data_index);

    /*ip 4 + mode byte 1*/
    fseek(qqwry_file,data_index+4,SEEK_SET);
    c=fgetc(qqwry_file);
    if (c==REDIRECT_TYPE_1) {
        fread(data_index_bytes,3,1,qqwry_file);
        data_index=LE_24(&data_index_bytes[0]);
        fseek(qqwry_file,data_index,SEEK_SET);
        c=fgetc(qqwry_file);
        /*制造一个假的4bytes位移,抵充ip*/
        data_index-=4;
    }

    if (c==REDIRECT_TYPE_2) {
        /*
         * ip 4 + mode byte 1 + addr1 offset 3
         * 这里ip的4个bytes不一定是真的,有可能是上一条注释里提到的情况
         */
        addr2_offset=data_index+8;
        fread(data_index_bytes,3,1,qqwry_file);

        data_index=LE_24(&data_index_bytes[0]);
        fseek(qqwry_file,data_index,SEEK_SET);
        while (c=fgetc(qqwry_file)) {
            addr1[strlen(addr1)]=c;
        }
        readOrJumpRead(addr2,qqwry_file,addr2_offset);
    } else {
        addr1[strlen(addr1)]=c;
        while (c=fgetc(qqwry_file)) {
            addr1[strlen(addr1)]=c;
        }
        readOrJumpRead(addr2,qqwry_file,0);
    }
    if (is_cz88(addr1)) {
        addr1[0]='/0';
    }
    if (is_cz88(addr2)) {
        addr2[0]='/0';
    }
    return 1;
}
int qqwry_get_location(char *addr1,char *addr2,const char *ip,FILE *qqwry_file) {
    return qqwry_get_location_by_long(addr1,addr2,ip2long(ip),qqwry_file);
}


int main()
{

 FILE *fp;
 fp = fopen("qqwry.dat", "r");
 if(!fp)
 {
  printf("open error/n");
 }
 char a1[256];
 char a2[256];
 qqwry_get_location(a1,a2,"61.152.108.1",fp);
 printf("%s %s/n",a1,a2);
 fclose(fp);

return 0;
}

 

 

 

 


#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "/usr/local/mysql/include/mysql.h"
#include "sql.h"
#include "uni.h"

int in_aton(const char *str)
{

        unsigned long l;

        unsigned int val;

        int i;
        l = 0;

        for (i = 0; i < 4; i++) {

                l <<= 8;

                if (*str != '/0') {

                        val = 0;

                        while (*str != '/0' && *str != '.') {

                                val *= 10;

                                val += *str - '0';

                                str++;

                        }

                        l |= val;

                        if (*str != '/0')

                                str++;

                }

        }
  return l;
       // return(htonl(l));

}

unsigned long ip_str2dec(char *ip_in) {
char *ip = strdup(ip_in);
unsigned long ip_dec = 0;
return in_aton(char *ip_in);
char *p;
int i;
for(i=0; i<3; i++) {
p = strrchr(ip, '.');
ip_dec |= atoi(p+1) << (8*i);
*p = '/0';
}
ip_dec |= atoi(ip) << (8*i);
free(ip);
return ip_dec;
}

unsigned long ip_arr2dec(char **ip_arr) {
unsigned long ip_dec = 0;
int i;
for(i=0; i<4; i++) {
ip_dec |= atoi(ip_arr[i]) << (8*(3-i));
}
return ip_dec;
}

unsigned long ip_arr2dec_r(unsigned char *ip_arr) {
unsigned long ip_dec = 0;
int i;
for(i=0; i<4; i++) {
ip_dec |= ip_arr[i] << (8*i);
}
return ip_dec;
}

/*****************************************/

typedef struct ip_info {
char ip[16];
char *country;
char *area;
char start_ip[16]; // For debug
char end_ip[16]; // For debug
char *mode; // For debug
} IP_INFO;

unsigned long get_long_addr3(unsigned char *buf);
char* get_string_by_addr(long addr, FILE *fp);
IP_INFO *get_ip_by_index(unsigned long index_addr, FILE *fp);
char* get_area(unsigned char* buffer, FILE *fp);
void print_iptable(FILE *fp);
unsigned long search_ip(char *ip_in, FILE *fp);

unsigned long get_long_addr3(unsigned char *buf)
{
 unsigned long addr = 0;
/* addr = buf[0] + buf[1]*256 + buf[2]*65536; */
 addr = buf[0] | buf[1] << 8 | buf[2] << 16;
 return addr;
}

char* get_string_by_addr(long addr, FILE *fp) {
unsigned char buffer[1024];
fseek(fp, addr, SEEK_SET);
fread(buffer, 1024, 1, fp);
return strdup(buffer);
}

IP_INFO *get_ip_by_index(unsigned long index_addr, FILE *fp)
{
 IP_INFO *ipinfo = (IP_INFO *)malloc(sizeof(IP_INFO));

 unsigned char ip[4];
 unsigned char addr[3];
 unsigned long record_addr = 0;

 fseek(fp, index_addr, SEEK_SET);
 fread(ip, 4, 1, fp);
 fread(addr, 3, 1, fp);
 record_addr = get_long_addr3(addr); //
 sprintf(ipinfo->start_ip, "%u.%u.%u.%u", ip[3], ip[2], ip[1], ip[0]);

 unsigned char buffer[1024];
 unsigned long country_addr;

 fseek(fp, record_addr, SEEK_SET);
 fread(ip, 4, 1, fp);
 fread(buffer, 1024, 1, fp); //
 sprintf(ipinfo->end_ip, "%u.%u.%u.%u", ip[3], ip[2], ip[1], ip[0]);

 if (buffer[0] == 1) {
 country_addr = get_long_addr3(buffer + 1);
 fseek(fp, country_addr, SEEK_SET);
 fread(buffer, 1024, 1, fp);

 if (buffer[0] == 2) {
 ipinfo->country = get_string_by_addr(get_long_addr3(buffer + 1), fp);
 ipinfo->area = get_area(buffer + 4, fp);
 ipinfo->mode = "1 + 2";
 } else {
 ipinfo->country = get_string_by_addr(country_addr, fp);
 ipinfo->area = get_area(buffer + strlen(ipinfo->country) + 1, fp);
 ipinfo->mode = "1 + D";
 }

 } else if (buffer[0] == 2) {
 ipinfo->country = get_string_by_addr(get_long_addr3(buffer + 1), fp);
 ipinfo->area = get_area(buffer + 4, fp);
 ipinfo->mode = "2 + D";

 } else {
 ipinfo->country = strdup(buffer);
 ipinfo->area = get_area(buffer + strlen(ipinfo->country) + 1, fp);
 ipinfo->mode = "D + D";
 }
 return ipinfo;
}

char* get_area(unsigned char* buffer, FILE *fp) {
if (buffer[0] == 1 || buffer[0] == 2) {
return get_string_by_addr(get_long_addr3(buffer + 1), fp);
} else {
return strdup(buffer);
}
}

 

void print_iptable(FILE *fp)
{
 unsigned long index_start, index_end;
 fseek(fp, 0, SEEK_SET);
 fread(&index_start, 4, 1, fp);
 fread(&index_end, 4, 1, fp);
 /* printf("%lu %lu/n", index_start, index_end); */

 unsigned long i;
 IP_INFO *ipinfo;
 char query[1024]={0};
 for(i=index_start; i<=index_end; i+=7)
 {
  ipinfo = get_ip_by_index(i, fp);
  //printf("%s - %s/n%s, %s/n", ipinfo->start_ip, ipinfo->end_ip, ipinfo->country, ipinfo->area);
  /*
  if(strstr(ipinfo->area,"CZ88"))
  {
   ipinfo->area="0";
   
  }
  */
  sprintf(query,"insert into IpArea(ia_from,ia_to,ia_from1,ia_to1,ia_country,ia_area)values('%s','%s',%d,%d,'%s','%s')",ipinfo->start_ip, ipinfo->end_ip,in_aton(ipinfo->start_ip),in_aton(ipinfo->end_ip), ipinfo->country, ipinfo->area);
  //printf("%s/n",query);
  //if(!strstr(ipinfo->area,"CZ88")&&!strstr(ipinfo->area,"CZ88")&&!strstr(ipinfo->area,"美国"))
  if(strstr(ipinfo->country,"市"))
  while(AddSql(query,strlen(query))==0)
  {
    sleep(30);
    printf("is full/n");
  }
  
  /*
  mysql_query( mysql,"set names gbk");
  mysql_query( mysql ,query);
  */
  free(ipinfo);
   }
}

unsigned long search_ip(char *ip_in, FILE *fp) {
unsigned long index_start, index_end, lo, hi, i, ip_i, ip_dest;
unsigned char ip_arr[4];

fseek(fp, 0, SEEK_SET);
fread(&index_start, 4, 1, fp);
fread(&index_end, 4, 1, fp);

lo = 0;
hi = (index_end - index_start) / 7;
ip_dest = ip_str2dec(ip_in);

while(lo <= hi) {
i = (lo + hi) / 2;

fseek(fp, index_start + i * 7, SEEK_SET);
fread(ip_arr, 4, 1, fp);
ip_i = ip_arr2dec_r(ip_arr);
if (ip_i == ip_dest)
return index_start + i * 7;
else if (ip_i < ip_dest)
lo = i + 1;
else
hi = i - 1;
}
/* hi return index_start + hi * 7;*/
}

int main(int argc, char **argv)
{
/*
 int ret;
 int i;
 pthread_t thread[1000];

 for(i=0;i<40;i++)
 {
  
  ret=pthread_create(&thread[i],NULL,(void*)cmdpool,NULL);
  if(ret!=0)
  {
   printf("Create cmdpool thread Failed/n ");
   
  }
  sleep(2);
 }
*/
 FILE *fp;
 fp = fopen("qqwry.dat", "r");
 if(!fp)
 {
  printf("open error/n");
 }
 //print_iptable(fp);
 printf("%s/n",argv[1]);
 IP_INFO *ipinfo = get_ip_by_index(search_ip(argv[1], fp), fp);
 printf("%s, %s/n", ipinfo->country, ipinfo->area);
 
 free(ipinfo);
 

 /* print_iptable(fp); */

 fclose(fp);

 //while(1) sleep(1);
 return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值