参考文章:
1. java版实现:
2. 纯真IP数据库格式详解:
以下是我的实现:使用的时候很简单:
- /**
- *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;
- }
阅读(5101) | 评论(0) | 转发(0) |