Linux下查询IP归属地的实现
时间:2014-08-31 02:21 来源:linux.it.net.cn 作者:it
以下是我的实现:使用的时候很简单:
点击(此处)折叠或打开
/**
*1.调用qqwry_init_parser创建一个qqwry_parser_t类型的解析器
*2.初始化一个存放查询结果信息的qqwry_record
*3.调用qqwry_querey_iprecord查询指定ip的归属地
*4.调用qqwry_release_parser释放资源
**/
qqwry_parser_t parser = qqwry_init_parser("/root/QQWry.Dat", VERBOSE_ENABLE,
CACHE_ENABLE, 1);
qqwry_record qr = QQWARY_RECORD_INITIALIZER();
qqwry_querey_iprecord(parser, "61.172.201.195", &qr);
qqwry_release_parser(parser);
这是一个初级版本,还没有经过大量的测试,可能存在很多不完备的地方,希望亲们试用了之后,能够提出改进意见啊。
qqwry_utils.h
点击(此处)折叠或打开
/*
* qqwry_utils.h
*
* Created on: 2012-4-26
* Author: zhanlin
*/
#ifndef QQWRY_UTILS_H_
#define QQWRY_UTILS_H_
int ipaddr_to_bytes(const char *src, char *dest);
void bytes_to_ipaddr(const char *src, char *dest);
inline int32_t char3_to_int32(const char *buf);
#endif /* QQWRY_UTILS_H_ */
qqwry_utils.c
点击(此处)折叠或打开
/*
* qqwry_utils.c
*
* Created on: 2012-4-26
* Author: zhanlin
*/
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "qqwry_utils.h"
int ipaddr_to_bytes(const char *src, char *dest) {
int n;
char *newstr;
char *sub;
int i = 0;
n = strlen(src);
newstr = (char *) malloc(n + 1);
if (newstr == NULL) {
return -1;
}
memcpy(newstr, src, n);
*(newstr + n) = 0;
sub = strtok(newstr, ".");
while (sub != NULL) {
// printf("%s atoi %d\n", sub, atoi(sub));
*(dest + i) = (char) atoi(sub);
sub = strtok(NULL, ".");
i++;
}
free(newstr);
return 0;
}
void bytes_to_ipaddr(const char *src, char *dest) {
sprintf(dest, "%c.%c.%c.%c", src[0], src[1], src[2], src[3]);
}
inline int32_t char3_to_int32(const char *buf) {
int32_t i = 0;
memcpy(&i, buf, 3);
return i;
}
qqwry_types.h
点击(此处)折叠或打开
/*
* qqwry_types.h
*
* Created on: 2012-4-26
* Author: zhanlin
*/
#ifndef QQWRY_TYPES_H_
#define QQWRY_TYPES_H_
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#pragma pack(0)
typedef struct _qqwry_header {
u_int32_t qh_idx_start;
u_int32_t qh_idx_end;
} qqwry_header, *qqwry_header_t;
#endif /* QQWRY_TYPES_H_ */
qqwry_parser.h
点击(此处)折叠或打开
/*
* qqwry_parser.h
*
* Created on: 2012-4-26
* Author: zhanlin
*/
#ifndef QQWRY_PARSER_H_
#define QQWRY_PARSER_H_
#include <sys/types.h>
enum {
VERBOSE_DISABLE = 0, VERBOSE_ENABLE = 1
};
enum {
CACHE_DISABLE = 0, CACHE_ENABLE = 1
};
typedef struct _qqwry_record {
char qr_ipaddr[20];
int32_t qr_ip;
char qr_bigzone[1024];
char qr_smallzone[1024];
} qqwry_record, *qqwry_record_t;
#define QQWARY_RECORD_INITIALIZER() {\
.qr_ipaddr = {0}, \
.qr_ip = 0, \
.qr_bigzone = {0}, \
.qr_smallzone = {0}, \
}
struct _qqwry_parser;
typedef struct _qqwry_parser qqwry_parser, *qqwry_parser_t;
qqwry_parser_t qqwry_init_parser(const char *dbpath, int verb, int cache,
int loaddb);
int qqwry_load_db(qqwry_parser_t parser);
void qqwry_unload_db(qqwry_parser_t parser);
int qqwry_querey_iprecord(qqwry_parser_t parser, const char *ipaddr, qqwry_record_t qr);
void qqwry_release_parser(qqwry_parser_t parser);
int load_db_to_mem(qqwry_parser_t parser);
#endif /* QQWRY_PARSER_H_ */
qqwry_types.c
点击(此处)折叠或打开
/*
* qqwry_types.c
*
* Created on: 2012-4-26
* Author: root
*/
#include "qqwry_parser.h"
#include "qqwry_utils.h"
#include "qqwry_types.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <iconv.h>
#include <arpa/inet.h>
#define trace(parser, fmt, …) {\
if((parser)->verbose) {\
printf(fmt, ##);\
}\
}
struct _qqwry_parser {
char qp_db_path[PATH_MAX];
int qp_db_fd;
int qp_verbose;
int qp_cache;
int qp_errno;
char *qp_memaddr;
u_int32_t qp_foff;
u_int32_t qp_fsize;
qqwry_header_t qp_header;
iconv_t qp_cd;
};
/*
int load_db_to_mem(qqwry_parser_t parser);
void unload_db(qqwry_parser_t parser);*/
int qqwry_load_db(qqwry_parser_t parser) {
struct stat buf;
int retval = 0;
parser->qp_errno = 0;
//
if ((retval = fstat(parser->qp_db_fd, &buf)) != 0) {
parser->qp_errno = errno;
if (parser->qp_verbose)
perror("fstat execute failed");
return retval;
}
//
parser->qp_fsize = buf.st_size;
parser->qp_memaddr = (char *) malloc(buf.st_size);
if (parser->qp_memaddr == NULL) {
parser->qp_errno = errno;
if (parser->qp_verbose)
perror("malloc execute failed");
return -1;
}
//
if ((retval = read(parser->qp_db_fd, parser->qp_memaddr, buf.st_size))
!= buf.st_size) {
parser->qp_errno = errno;
if (parser->qp_verbose)
perror("read file failed");
}
parser->qp_header = (qqwry_header_t) parser->qp_memaddr;
//
parser->qp_cd = iconv_open("UTF-8", "GBK");
return 0;
}
void qqwry_unload_db(qqwry_parser_t parser) {
if (parser->qp_memaddr) {
free(parser->qp_memaddr);
parser->qp_memaddr = NULL;
}
if (parser->qp_cd) {
iconv_close(parser->qp_cd);
}
}
int qqwry_open_db(qqwry_parser_t parser) {
parser->qp_db_fd = open(parser->qp_db_path, O_RDONLY, 0777);
parser->qp_errno = errno;
if (parser->qp_verbose && parser->qp_db_fd < 0)
perror("open qqwry datafile failed");
return parser->qp_db_fd;
}
void qqwry_close_db(qqwry_parser_t parser) {
if (parser->qp_db_fd >= 0) {
close(parser->qp_db_fd);
parser->qp_db_fd = -1;
}
}
int qqwry_read(qqwry_parser_t p, void *buf, int n) {
if (p->qp_fsize < p->qp_foff + n) {
n = p->qp_fsize - p->qp_foff;
}
memcpy(buf, (p->qp_memaddr + p->qp_foff), n);
p->qp_foff += n;
return n;
}
int qqwry_seek(qqwry_parser_t p, int32_t off) {
if (p->qp_fsize < off) {
return -1;
}
return (p->qp_foff = off);
}
int32_t qqwry_read3c_to_int32(qqwry_parser_t p) {
char b3[3] = { 0 };
int32_t ret = 0;
if (qqwry_read(p, b3, 3) != 3) {
return -1;
}
ret |= (b3[0] & 0xFF);
ret |= ((b3[1] 《 8) & 0xFF00);
ret |= ((b3[2] 《 16) & 0xFF0000);
return ret;
}
char qqwry_readc(qqwry_parser_t p) {
char b[1] = { 0 };
if (qqwry_read(p, b, 1) != 1) {
return -1;
}
return b[0];
}
int qqwry_read_ip(qqwry_parser_t p, int32_t offset, int32_t *ip) {
int ret = 0;
ret = qqwry_seek(p, offset);
if (ret < 0)
return ret;
ret = qqwry_read(p, ip, 4);
*ip = ntohl(*ip);
return ret;
}
/**
* 把两个byte当作无符号数进行比较
*
* @param b1
* @param b2
* @return 若b1大于b2则返回1,相等返回0,小于返回-1
*/
int qqwry_compare_char(char c1, char c2) {
if ((c1 & 0xFF) > (c2 & 0xFF)) // 比较是否大于
return 1;
else if ((c1 ^ c2) == 0) // 判断是否相等
return 0;
else
return -1;
}
/**
* 把类成员ip和beginIp比较,注意这个beginIp是big-endian的
*
* @param ip
* 要查询的IP
* @param beginIp
* 和被查询IP相比较的IP
* @return 相等返回0,ip大于beginIp则返回1,小于返回-1。
*/
inline int qqwry_compare_ip(int32_t *ip, int32_t *beginip) {
char *ipc = (char *) ip;
char *beginipc = (char *) beginip;
int i = 0;
for (; i < 4; i++) {
int r = qqwry_compare_char((*(ipc + i)), *(beginipc + i));
if (r != 0)
return r;
}
return 0;
}
qqwry_parser_t qqwry_init_parser(const char *dbpath, int verb, int cache,
int loaddb) {
qqwry_parser_t qp = (qqwry_parser_t) malloc(sizeof(qqwry_parser));
if (qp) {
//
qp->qp_cache = cache;
qp->qp_errno = 0;
qp->qp_db_fd = -1;
qp->qp_verbose = verb;
qp->qp_memaddr = NULL;
qp->qp_foff = 0;
qp->qp_header = NULL;
strncpy(qp->qp_db_path, dbpath, PATH_MAX);
//
if (loaddb) {
if (qqwry_open_db(qp) >= 0) {
if (qqwry_load_db(qp) != 0)
qp->qp_errno = errno;
else
qqwry_close_db(qp);
} else {
qp->qp_errno = errno;
}
}
}
return qp;
}
int32_t get_middle_offset(int32_t begin, int32_t end) {
#define IP_RECORD_LENGTH 7
long records = (end - begin) / IP_RECORD_LENGTH;
records 》= 1;
if (records == 0)
records = 1;
return begin + records * IP_RECORD_LENGTH;
}
int32_t qqwry_locate_ip(qqwry_parser_t p, const char *ipaddr) {
int32_t ip = 0;
int32_t rip;
int ret = 0;
int32_t m;
int32_t i = p->qp_header->qh_idx_start;
int j = p->qp_header->qh_idx_end;
ip = (int32_t) inet_addr(ipaddr) ;
// ipaddr_to_bytes(ipaddr, (char *) &ip);
qqwry_read_ip(p, p->qp_header->qh_idx_start, &rip);
ret = qqwry_compare_ip(&ip, &rip);
if (ret == 0)
return p->qp_header->qh_idx_start;
else if (ret < 0)
return -1;
// 开始二分搜索
for (; i < j;) {
m = get_middle_offset(i, j);
qqwry_read_ip(p, m, &rip);
ret = qqwry_compare_ip(&ip, &rip);
// log.debug(Utils.getIpStringFromBytes(b));
if (ret > 0)
i = m;
else if (ret < 0) {
if (m == j) {
j -= IP_RECORD_LENGTH;
m = j;
} else {
j = m;
}
} else {
qqwry_seek(p, m + 4);
return qqwry_read3c_to_int32(p);
}
}
// 如果循环结束了,那么i和j必定是相等的,这个记录为最可能的记录,但是并非
// 肯定就是,还要检查一下,如果是,就返回结束地址区的绝对偏移
qqwry_seek(p, m + 4);
m = qqwry_read3c_to_int32(p);
qqwry_read_ip(p, m, &rip);
ret = qqwry_compare_ip(&ip, &rip);
if (ret <= 0)
return m;
else
return -1;
}
size_t conver_gbk_to_utf8(qqwry_parser_t p, char *inbuf, char *outbuf) {
int n = strlen(inbuf);
char *in = inbuf;
char *out = outbuf;
size_t outlen = n * 4;
iconv(p->qp_cd, &in, (size_t *) &n, &out, &outlen);
outlen = strlen(outbuf);
return outlen;
}
void qqwry_read_string(qqwry_parser_t p, char *buf) {
int i = 0;
char tmp[512] = { 0 };
for (i = 0, tmp[i] = qqwry_readc(p); tmp[i] != 0; tmp[++i] = qqwry_readc(p))
;
conver_gbk_to_utf8(p, tmp, buf);
}
void qqwry_read_smallzone(qqwry_parser_t p, char *buf) {
char flag = qqwry_readc(p);
if (flag == 0x01 || flag == 0x02) {
long areaOffset = qqwry_read3c_to_int32(p);
if (areaOffset == 0)
p->qp_errno = 0;
else {
qqwry_seek(p, areaOffset);
qqwry_read_string(p, buf);
}
} else {
return qqwry_read_string(p, buf);
}
}
int qqwry_querey_iprecord(qqwry_parser_t parser, const char *ipaddr,
qqwry_record_t qr) {
#define AREA_FOLLOWED 0x1
#define NO_AREA 0x2
int32_t offset = qqwry_locate_ip(parser, ipaddr);
char flag = 0;
printf("ip off: %d\n", offset);
qqwry_seek(parser, offset + 4);
// 读取第一个字节判断是否标志字节
flag = qqwry_readc(parser);
if (flag == AREA_FOLLOWED) {
// 读取国家偏移
int32_t country_offset = qqwry_read3c_to_int32(parser);
// 跳转至偏移处
qqwry_seek(parser, country_offset);
// 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向
flag = qqwry_readc(parser);
if (flag == NO_AREA) {
qqwry_seek(parser, qqwry_read3c_to_int32(parser));
qqwry_read_string(parser, qr->qr_bigzone);
qqwry_seek(parser, country_offset + 4);
} else {
qqwry_seek(parser, country_offset);
qqwry_read_string(parser, qr->qr_bigzone);
}
// 读取地区标志
qqwry_read_smallzone(parser, qr->qr_smallzone);
} else if (flag == NO_AREA) {
int32_t country_offset = qqwry_read3c_to_int32(parser);
qqwry_seek(parser, country_offset);
qqwry_read_string(parser, qr->qr_bigzone);
qqwry_seek(parser, offset + 8);
qqwry_read_string(parser, qr->qr_smallzone);
} else {
qqwry_seek(parser, parser->qp_foff - 1);
qqwry_read_string(parser, qr->qr_bigzone);
qqwry_read_string(parser, qr->qr_smallzone);
}
return 0;
}
void qqwry_release_parser(qqwry_parser_t parser) {
if (parser != NULL) {
//
if (parser->qp_memaddr) {
qqwry_unload_db(parser);
}
//
free(parser);
parser = NULL;
}
}
ipinfo.c
点击(此处)折叠或打开
/*
============================================================================
Name : ipinfo.c
Author : ZhanLin
Version :
Copyright : GPL v2
Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qqwry_parser.h"
#include <iconv.h>
int main(void) {
qqwry_parser_t parser = qqwry_init_parser("/root/QQWry.Dat", VERBOSE_ENABLE,
CACHE_ENABLE, 1);
qqwry_record qr = QQWARY_RECORD_INITIALIZER();
qqwry_querey_iprecord(parser, "61.172.201.195", &qr);
qqwry_release_parser(parser);
printf("big zone: %s, small zone: %s\n", qr.qr_bigzone, qr.qr_smallzone);
return EXIT_SUCCESS;
}
(责任编辑:IT)
以下是我的实现:使用的时候很简单: 点击(此处)折叠或打开 /** *1.调用qqwry_init_parser创建一个qqwry_parser_t类型的解析器 *2.初始化一个存放查询结果信息的qqwry_record *3.调用qqwry_querey_iprecord查询指定ip的归属地 *4.调用qqwry_release_parser释放资源 **/ qqwry_parser_t parser = qqwry_init_parser("/root/QQWry.Dat", VERBOSE_ENABLE, CACHE_ENABLE, 1); qqwry_record qr = QQWARY_RECORD_INITIALIZER(); qqwry_querey_iprecord(parser, "61.172.201.195", &qr); qqwry_release_parser(parser); 这是一个初级版本,还没有经过大量的测试,可能存在很多不完备的地方,希望亲们试用了之后,能够提出改进意见啊。 qqwry_utils.h 点击(此处)折叠或打开 /* * qqwry_utils.h * * Created on: 2012-4-26 * Author: zhanlin */ #ifndef QQWRY_UTILS_H_ #define QQWRY_UTILS_H_ int ipaddr_to_bytes(const char *src, char *dest); void bytes_to_ipaddr(const char *src, char *dest); inline int32_t char3_to_int32(const char *buf); #endif /* QQWRY_UTILS_H_ */ qqwry_utils.c 点击(此处)折叠或打开 /* * qqwry_utils.c * * Created on: 2012-4-26 * Author: zhanlin */ #include <string.h> #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "qqwry_utils.h" int ipaddr_to_bytes(const char *src, char *dest) { int n; char *newstr; char *sub; int i = 0; n = strlen(src); newstr = (char *) malloc(n + 1); if (newstr == NULL) { return -1; } memcpy(newstr, src, n); *(newstr + n) = 0; sub = strtok(newstr, "."); while (sub != NULL) { // printf("%s atoi %d\n", sub, atoi(sub)); *(dest + i) = (char) atoi(sub); sub = strtok(NULL, "."); i++; } free(newstr); return 0; } void bytes_to_ipaddr(const char *src, char *dest) { sprintf(dest, "%c.%c.%c.%c", src[0], src[1], src[2], src[3]); } inline int32_t char3_to_int32(const char *buf) { int32_t i = 0; memcpy(&i, buf, 3); return i; } qqwry_types.h 点击(此处)折叠或打开 /* * qqwry_types.h * * Created on: 2012-4-26 * Author: zhanlin */ #ifndef QQWRY_TYPES_H_ #define QQWRY_TYPES_H_ #include <sys/types.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <dirent.h> #pragma pack(0) typedef struct _qqwry_header { u_int32_t qh_idx_start; u_int32_t qh_idx_end; } qqwry_header, *qqwry_header_t; #endif /* QQWRY_TYPES_H_ */ qqwry_parser.h 点击(此处)折叠或打开 /* * qqwry_parser.h * * Created on: 2012-4-26 * Author: zhanlin */ #ifndef QQWRY_PARSER_H_ #define QQWRY_PARSER_H_ #include <sys/types.h> enum { VERBOSE_DISABLE = 0, VERBOSE_ENABLE = 1 }; enum { CACHE_DISABLE = 0, CACHE_ENABLE = 1 }; typedef struct _qqwry_record { char qr_ipaddr[20]; int32_t qr_ip; char qr_bigzone[1024]; char qr_smallzone[1024]; } qqwry_record, *qqwry_record_t; #define QQWARY_RECORD_INITIALIZER() {\ .qr_ipaddr = {0}, \ .qr_ip = 0, \ .qr_bigzone = {0}, \ .qr_smallzone = {0}, \ } struct _qqwry_parser; typedef struct _qqwry_parser qqwry_parser, *qqwry_parser_t; qqwry_parser_t qqwry_init_parser(const char *dbpath, int verb, int cache, int loaddb); int qqwry_load_db(qqwry_parser_t parser); void qqwry_unload_db(qqwry_parser_t parser); int qqwry_querey_iprecord(qqwry_parser_t parser, const char *ipaddr, qqwry_record_t qr); void qqwry_release_parser(qqwry_parser_t parser); int load_db_to_mem(qqwry_parser_t parser); #endif /* QQWRY_PARSER_H_ */ qqwry_types.c 点击(此处)折叠或打开 /* * qqwry_types.c * * Created on: 2012-4-26 * Author: root */ #include "qqwry_parser.h" #include "qqwry_utils.h" #include "qqwry_types.h" #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <iconv.h> #include <arpa/inet.h> #define trace(parser, fmt, …) {\ if((parser)->verbose) {\ printf(fmt, ##);\ }\ } struct _qqwry_parser { char qp_db_path[PATH_MAX]; int qp_db_fd; int qp_verbose; int qp_cache; int qp_errno; char *qp_memaddr; u_int32_t qp_foff; u_int32_t qp_fsize; qqwry_header_t qp_header; iconv_t qp_cd; }; /* int load_db_to_mem(qqwry_parser_t parser); void unload_db(qqwry_parser_t parser);*/ int qqwry_load_db(qqwry_parser_t parser) { struct stat buf; int retval = 0; parser->qp_errno = 0; // if ((retval = fstat(parser->qp_db_fd, &buf)) != 0) { parser->qp_errno = errno; if (parser->qp_verbose) perror("fstat execute failed"); return retval; } // parser->qp_fsize = buf.st_size; parser->qp_memaddr = (char *) malloc(buf.st_size); if (parser->qp_memaddr == NULL) { parser->qp_errno = errno; if (parser->qp_verbose) perror("malloc execute failed"); return -1; } // if ((retval = read(parser->qp_db_fd, parser->qp_memaddr, buf.st_size)) != buf.st_size) { parser->qp_errno = errno; if (parser->qp_verbose) perror("read file failed"); } parser->qp_header = (qqwry_header_t) parser->qp_memaddr; // parser->qp_cd = iconv_open("UTF-8", "GBK"); return 0; } void qqwry_unload_db(qqwry_parser_t parser) { if (parser->qp_memaddr) { free(parser->qp_memaddr); parser->qp_memaddr = NULL; } if (parser->qp_cd) { iconv_close(parser->qp_cd); } } int qqwry_open_db(qqwry_parser_t parser) { parser->qp_db_fd = open(parser->qp_db_path, O_RDONLY, 0777); parser->qp_errno = errno; if (parser->qp_verbose && parser->qp_db_fd < 0) perror("open qqwry datafile failed"); return parser->qp_db_fd; } void qqwry_close_db(qqwry_parser_t parser) { if (parser->qp_db_fd >= 0) { close(parser->qp_db_fd); parser->qp_db_fd = -1; } } int qqwry_read(qqwry_parser_t p, void *buf, int n) { if (p->qp_fsize < p->qp_foff + n) { n = p->qp_fsize - p->qp_foff; } memcpy(buf, (p->qp_memaddr + p->qp_foff), n); p->qp_foff += n; return n; } int qqwry_seek(qqwry_parser_t p, int32_t off) { if (p->qp_fsize < off) { return -1; } return (p->qp_foff = off); } int32_t qqwry_read3c_to_int32(qqwry_parser_t p) { char b3[3] = { 0 }; int32_t ret = 0; if (qqwry_read(p, b3, 3) != 3) { return -1; } ret |= (b3[0] & 0xFF); ret |= ((b3[1] 《 8) & 0xFF00); ret |= ((b3[2] 《 16) & 0xFF0000); return ret; } char qqwry_readc(qqwry_parser_t p) { char b[1] = { 0 }; if (qqwry_read(p, b, 1) != 1) { return -1; } return b[0];
} int qqwry_read_ip(qqwry_parser_t p, int32_t offset, int32_t *ip) { int ret = 0; ret = qqwry_seek(p, offset); if (ret < 0) return ret; ret = qqwry_read(p, ip, 4); *ip = ntohl(*ip); return ret; } /** * 把两个byte当作无符号数进行比较 * * @param b1 * @param b2 * @return 若b1大于b2则返回1,相等返回0,小于返回-1 */ int qqwry_compare_char(char c1, char c2) { if ((c1 & 0xFF) > (c2 & 0xFF)) // 比较是否大于 return 1; else if ((c1 ^ c2) == 0) // 判断是否相等 return 0; else return -1; } /** * 把类成员ip和beginIp比较,注意这个beginIp是big-endian的 * * @param ip * 要查询的IP * @param beginIp * 和被查询IP相比较的IP * @return 相等返回0,ip大于beginIp则返回1,小于返回-1。 */ inline int qqwry_compare_ip(int32_t *ip, int32_t *beginip) { char *ipc = (char *) ip; char *beginipc = (char *) beginip; int i = 0; for (; i < 4; i++) { int r = qqwry_compare_char((*(ipc + i)), *(beginipc + i)); if (r != 0) return r; } return 0; } qqwry_parser_t qqwry_init_parser(const char *dbpath, int verb, int cache, int loaddb) { qqwry_parser_t qp = (qqwry_parser_t) malloc(sizeof(qqwry_parser)); if (qp) { // qp->qp_cache = cache; qp->qp_errno = 0; qp->qp_db_fd = -1; qp->qp_verbose = verb; qp->qp_memaddr = NULL; qp->qp_foff = 0; qp->qp_header = NULL; strncpy(qp->qp_db_path, dbpath, PATH_MAX); // if (loaddb) { if (qqwry_open_db(qp) >= 0) { if (qqwry_load_db(qp) != 0) qp->qp_errno = errno; else qqwry_close_db(qp); } else { qp->qp_errno = errno; } } } return qp; } int32_t get_middle_offset(int32_t begin, int32_t end) { #define IP_RECORD_LENGTH 7 long records = (end - begin) / IP_RECORD_LENGTH; records 》= 1; if (records == 0) records = 1; return begin + records * IP_RECORD_LENGTH; } int32_t qqwry_locate_ip(qqwry_parser_t p, const char *ipaddr) { int32_t ip = 0; int32_t rip; int ret = 0; int32_t m; int32_t i = p->qp_header->qh_idx_start; int j = p->qp_header->qh_idx_end; ip = (int32_t) inet_addr(ipaddr) ; // ipaddr_to_bytes(ipaddr, (char *) &ip); qqwry_read_ip(p, p->qp_header->qh_idx_start, &rip); ret = qqwry_compare_ip(&ip, &rip); if (ret == 0) return p->qp_header->qh_idx_start; else if (ret < 0) return -1; // 开始二分搜索 for (; i < j;) { m = get_middle_offset(i, j); qqwry_read_ip(p, m, &rip); ret = qqwry_compare_ip(&ip, &rip); // log.debug(Utils.getIpStringFromBytes(b)); if (ret > 0) i = m; else if (ret < 0) { if (m == j) { j -= IP_RECORD_LENGTH; m = j; } else { j = m; } } else { qqwry_seek(p, m + 4); return qqwry_read3c_to_int32(p); }
} // 如果循环结束了,那么i和j必定是相等的,这个记录为最可能的记录,但是并非 // 肯定就是,还要检查一下,如果是,就返回结束地址区的绝对偏移 qqwry_seek(p, m + 4); m = qqwry_read3c_to_int32(p); qqwry_read_ip(p, m, &rip); ret = qqwry_compare_ip(&ip, &rip); if (ret <= 0) return m; else return -1; } size_t conver_gbk_to_utf8(qqwry_parser_t p, char *inbuf, char *outbuf) { int n = strlen(inbuf); char *in = inbuf; char *out = outbuf; size_t outlen = n * 4; iconv(p->qp_cd, &in, (size_t *) &n, &out, &outlen); outlen = strlen(outbuf); return outlen; } void qqwry_read_string(qqwry_parser_t p, char *buf) { int i = 0; char tmp[512] = { 0 }; for (i = 0, tmp[i] = qqwry_readc(p); tmp[i] != 0; tmp[++i] = qqwry_readc(p)) ; conver_gbk_to_utf8(p, tmp, buf); } void qqwry_read_smallzone(qqwry_parser_t p, char *buf) { char flag = qqwry_readc(p); if (flag == 0x01 || flag == 0x02) { long areaOffset = qqwry_read3c_to_int32(p); if (areaOffset == 0) p->qp_errno = 0; else { qqwry_seek(p, areaOffset); qqwry_read_string(p, buf); } } else { return qqwry_read_string(p, buf); } } int qqwry_querey_iprecord(qqwry_parser_t parser, const char *ipaddr, qqwry_record_t qr) { #define AREA_FOLLOWED 0x1 #define NO_AREA 0x2 int32_t offset = qqwry_locate_ip(parser, ipaddr); char flag = 0; printf("ip off: %d\n", offset); qqwry_seek(parser, offset + 4); // 读取第一个字节判断是否标志字节 flag = qqwry_readc(parser); if (flag == AREA_FOLLOWED) { // 读取国家偏移 int32_t country_offset = qqwry_read3c_to_int32(parser); // 跳转至偏移处 qqwry_seek(parser, country_offset); // 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向 flag = qqwry_readc(parser); if (flag == NO_AREA) { qqwry_seek(parser, qqwry_read3c_to_int32(parser)); qqwry_read_string(parser, qr->qr_bigzone); qqwry_seek(parser, country_offset + 4); } else { qqwry_seek(parser, country_offset); qqwry_read_string(parser, qr->qr_bigzone); } // 读取地区标志 qqwry_read_smallzone(parser, qr->qr_smallzone); } else if (flag == NO_AREA) { int32_t country_offset = qqwry_read3c_to_int32(parser); qqwry_seek(parser, country_offset); qqwry_read_string(parser, qr->qr_bigzone); qqwry_seek(parser, offset + 8); qqwry_read_string(parser, qr->qr_smallzone); } else { qqwry_seek(parser, parser->qp_foff - 1); qqwry_read_string(parser, qr->qr_bigzone); qqwry_read_string(parser, qr->qr_smallzone); } return 0; } void qqwry_release_parser(qqwry_parser_t parser) { if (parser != NULL) { // if (parser->qp_memaddr) { qqwry_unload_db(parser); } // free(parser); parser = NULL; } } ipinfo.c 点击(此处)折叠或打开 /* ============================================================================ Name : ipinfo.c Author : ZhanLin Version : Copyright : GPL v2 Ansi-style ============================================================================ */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "qqwry_parser.h" #include <iconv.h> int main(void) { qqwry_parser_t parser = qqwry_init_parser("/root/QQWry.Dat", VERBOSE_ENABLE, CACHE_ENABLE, 1); qqwry_record qr = QQWARY_RECORD_INITIALIZER(); qqwry_querey_iprecord(parser, "61.172.201.195", &qr); qqwry_release_parser(parser); printf("big zone: %s, small zone: %s\n", qr.qr_bigzone, qr.qr_smallzone); return EXIT_SUCCESS; } (责任编辑:IT) |