这次又贴一个小程序,是根据luma所写的关于纯真ip数据库格式说明文档而完成了。luma的文章链接地址为:
http://lumaqq.linuxsir.org/article/qqwry_format_detail.html
本代码借鉴了文中已经贴出的部分java代码的片段
本程序可以根据输入的ip地址,显示其对应的地理信息,信息来源于纯真ip数据库文件"QQWry.Dat",从网上所搜可以很容易下载到
/**
* file: getipinfo.c
* author: rare
* date: 2008/12/02
* email: dux003#163.com
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define MAX_BUF_LEN 128
static void usage()
{
printf("usage:/n");
printf("/tgetipinfo xxx.xxx.xxx.xxx/n");
exit(0);
}
static int readint3(FILE* fp)
{
int val;
unsigned char byte[3];
fread(byte, 1, 3, fp);
val = byte[0] & 0xFF;
val |= (byte[1]<< 8) & 0xFF00;
val |= (byte[2]<<16) & 0xFF0000;
return val;
}
static void readstring(FILE* fp, char* strbuf, int* len)
{
int i = 0;
fread(&strbuf[i], 1, 1, fp);
while (strbuf[i] != 0 && i<(*len)-1)
{
i++;
fread(&strbuf[i], 1, 1, fp);
}
if (strbuf[i] != 0)
strbuf[i] = 0;
*len = i;
}
static int findrecoffset(FILE* fp, unsigned int ip)
{
int first_index_pos, last_index_pos;
unsigned int fip, lip, tip;
int rec_pos;
int tmp;
//read first index item offset
fread(&first_index_pos, 1, 4, fp);
//read last index item offset
fread(&last_index_pos, 1, 4, fp);
while (first_index_pos+7 < last_index_pos)
{
fseek(fp, first_index_pos, SEEK_SET);
fread(&fip, 1, 4, fp);
fseek(fp, last_index_pos, SEEK_SET);
fread(&lip, 1, 4, fp);
if (ip > lip)
{
first_index_pos = last_index_pos; //tricks to exit loop
last_index_pos += 7;
}
else //must be in range(fip, lip)
{
tmp = first_index_pos + (last_index_pos-first_index_pos)/14*7;
fseek(fp, tmp, SEEK_SET);
fread(&tip, 1, 4, fp);
if (ip > tip)
first_index_pos = tmp;
else
last_index_pos = tmp;
}
}
fseek(fp, first_index_pos, SEEK_SET);
fread(&fip, 1, 4, fp);
rec_pos = readint3(fp);
fseek(fp, rec_pos, SEEK_SET);
fread(&lip, 1, 4, fp);
if (ip<fip || ip>lip)
return -1;
return rec_pos;
}
static void readipinfo(FILE* fp, int offset)
{
unsigned char mode;
int rec_pos;
int buflen;
char country[MAX_BUF_LEN];
char area[MAX_BUF_LEN];
//read information from offset rec_pos
fseek(fp, offset, SEEK_SET);
fseek(fp, 4, SEEK_CUR);
fread(&mode, 1, 1, fp);
if (mode == 1) //redirection mode 1
{
rec_pos = readint3(fp);
fseek(fp, rec_pos, SEEK_SET);
fread(&mode, 1, 1, fp);
if (mode == 2)
{
rec_pos = readint3(fp);
buflen = MAX_BUF_LEN;
readstring(fp, area, &buflen);
fseek(fp, rec_pos, SEEK_SET);
buflen = MAX_BUF_LEN;
readstring(fp, country, &buflen);
printf("country:%s/n", (char*)country);
printf("area:%s/n", (char*)area);
}
else
{
//move back one byte
fseek(fp, -1, SEEK_CUR);
buflen = MAX_BUF_LEN;
readstring(fp, country, &buflen);
buflen = MAX_BUF_LEN;
readstring(fp, area, &buflen);
printf("country:%s/n", (char*)country);
printf("area:%s/n", (char*)area);
}
}
else if (mode == 2) //redirection mode 2
{
rec_pos = readint3(fp);
buflen = MAX_BUF_LEN;
readstring(fp, area, &buflen);
fseek(fp, rec_pos, SEEK_SET);
buflen = MAX_BUF_LEN;
readstring(fp, country, &buflen);
printf("country:%s/n", (char*)country);
printf("area:%s/n", (char*)area);
}
else //no redirection
{
//move back one byte
fseek(fp, -1, SEEK_CUR);
buflen = MAX_BUF_LEN;
readstring(fp, country, &buflen);
buflen = MAX_BUF_LEN;
readstring(fp, area, &buflen);
printf("country:%s/n", (char*)country);
printf("area:%s/n", (char*)area);
}
}
static int getipinfo(in_addr_t ip)
{
FILE* fp;
unsigned int nip;
int rec_pos;
const unsigned int cnip = ntohl(ip);
fp = fopen("QQWry.Dat", "rb");
if (fp == NULL)
{
fprintf(stderr, "open ip database error!/n");
return -1;
}
if ((rec_pos = findrecoffset(fp, cnip)) == -1)
{
fprintf(stderr, "can not find record of the ip address/n");
fclose(fp);
return -1;
}
readipinfo(fp, rec_pos);
fclose(fp);
return 0;
}
int main(int argc, char** argv)
{
in_addr_t ip;
//check input
if (argc != 2)
usage();
ip = inet_addr(argv[1]);
if (ip == 0xFFFFFFFF)
{
printf("invalid ip address/n");
exit(1);
}
//get ip information
getipinfo(ip);
return 0;
}
//运行效果
rare@rare:~/mysrc/qqwry$ ./getipinfo 59.66.122.77
country:清华大学
area:26#楼
注意:运行程序的conosle编码格式必须设置为GBK,这是纯真ip数据库采用的编码格式,否则中文会显示为乱码
要读取纯真ip数据库版本信息,则执行 ./getipinfo 255.255.255.*
其中“*”为1至254都可。以下是我所采用的版本
rare@rare:~/mysrc/qqwry$ ./getipinfo 255.255.255.1
country:纯真网络
area:2008年11月30日IP数据