Skip to content

Commit

Permalink
Merge pull request #3 from mingcheng/master
Browse files Browse the repository at this point in the history
增加在线获取最新数据库并直接运行
  • Loading branch information
freshcn authored May 20, 2019
2 parents 03c6e87 + 21797b2 commit bb0d1d8
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 24 deletions.
31 changes: 24 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
# qqwry
# qqwry.go

[![travis ci](https://travis-ci.org/freshcn/qqwry.svg?branch=master)](https://travis-ci.org/freshcn/qqwry)

纯真 IP 库的一个服务。通过http提供一个ip地址归属地查询支持
通过 HTTP 提供一个 IP 地址归属地查询支持的微服务,使用纯真的 IP 库(支持直接在线获取和更新)。

## 软件介绍
## 介绍

我们大家做网站的时候,都会需要将用户的IP地址转换为归属地址功能,而之前的作法大都是从硬盘的数据文件中读取,这样不太高效。我这次将纯真IP库直接加载到内存中,并以http服务的方式提供接口出来。这样方便自己项目中所有的程序都能方便的接口IP查询功能了。
![Screenshots](screenshots.png)

我们大家做网站的时候,都会需要将用户的IP地址转换为归属地址功能,而之前的作法大都是从硬盘的数据文件中读取,这样不太高效。

这个微服务将纯真 IP 库直接加载到内存中,并以 HTTP 方式提供接口暴露出来(后续支持 GRPC),这样方便项目中所有的程序都能方便的接口 IP 查询功能。

## 安装

### go安装
### Golang 的安装

```
go get github.com/freshcn/qqwry
```

### 二进制包直接下载

https://github.com/freshcn/qqwry/releases

### 在线获取最新的纯真 IP 库

默认支持在线获取最新的纯真 IP 库,解压缩到内村中并直接运行(需要网络的支持)。如果您想使用本地下载运行,请参考如下。

### 下载纯真IP库
请访问 http://www.cz88.net 下载纯真IP库,需要在windows中安装程序,然后在程序的安装目录可以找到qqwry.dat文件,复制出来放到和本程序同一个目录(当然也可是其他目录,只是需要在运行的时候指定IP库目录),

访问 http://www.cz88.net 下载纯真IP库,需要在 Windows 中安装程序,然后在程序的安装目录可以找到 `qqwry.dat` 文件;也可以考虑运行使用 `download.go``GetOnline` 函数并将数据保存为本地文件。

将 dump 出来的 `qqwry` 文件放到和本程序同一目录(当然也可是其他目录,只是需要在运行的时候指定IP库目录),直接运行即可。

### 运行参数

运行 ./qqwry -h 可以看到本服务程序的可用运行参数
运行 `./qqwry -h` 可以看到本服务程序的可用运行参数

```
-port string
Expand All @@ -34,6 +46,7 @@ https://github.com/freshcn/qqwry/releases
```

## 使用方法

```
http://127.0.0.1:2060?ip=8.8.8.8,114.114.114.114&callback=a
```
Expand All @@ -46,6 +59,7 @@ http://127.0.0.1:2060?ip=8.8.8.8,114.114.114.114&callback=a
```json
{"114.114.114.114":{"ip":"114.114.114.114","country":"江苏省南京市","area":"南京信风网络科技有限公司GreatbitDNS服务器"},"8.8.8.8":{"ip":"8.8.8.8","country":"美国","area":"加利福尼亚州圣克拉拉县山景市谷歌公司DNS服务器"}}
```

* ip - 输入的ip地址
* country - 国家或地区
* area - 区域(我实际测试得到还有可能是运营商)
Expand All @@ -55,3 +69,6 @@ http://127.0.0.1:2060?ip=8.8.8.8,114.114.114.114&callback=a

* 感谢[纯真IP库](http://www.cz88.net)一直以来坚持为大家提供免费的IP库资源
* 感谢[yinheli](https://github.com/yinheli)[qqwry](https://github.com/yinheli/qqwry)项目,为我提供了纯真ip库文件格式算法
* 感谢 https://zhangzifan.com/update-qqwry-dat.html 提供在线获取 IP 库的方案

`- eof -`
57 changes: 57 additions & 0 deletions download.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import (
"bytes"
"compress/zlib"
"encoding/binary"
"io/ioutil"
"net/http"
)

// @ref https://zhangzifan.com/update-qqwry-dat.html

func getKey() (uint32, error) {
resp, err := http.Get("http://update.cz88.net/ip/copywrite.rar")
if err != nil {
return 0, err
}
defer resp.Body.Close()

if body, err := ioutil.ReadAll(resp.Body); err != nil {
return 0, err
} else {
// @see https://stackoverflow.com/questions/34078427/how-to-read-packed-binary-data-in-go
return binary.LittleEndian.Uint32(body[5*4:]), nil
}
}

func GetOnline() ([]byte, error) {
resp, err := http.Get("http://update.cz88.net/ip/qqwry.rar")
if err != nil {
return nil, err
}
defer resp.Body.Close()

if body, err := ioutil.ReadAll(resp.Body); err != nil {
return nil, err
} else {
if key, err := getKey(); err != nil {
return nil, err
} else {
for i := 0; i < 0x200; i++ {
key = key * 0x805
key++
key = key & 0xff

body[i] = byte(uint32(body[i]) ^ key)
}

reader, err := zlib.NewReader(bytes.NewReader(body))
if err != nil {
return nil, err
}

return ioutil.ReadAll(reader)
}
}
}
22 changes: 22 additions & 0 deletions download.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
// PHP 纯真 IP 地址数据库自动更新功能
// @from https://zhangzifan.com/update-qqwry-dat.html
$copywrite = file_get_contents("http://update.cz88.net/ip/copywrite.rar");
$qqwry = file_get_contents("http://update.cz88.net/ip/qqwry.rar");

$key = unpack("V6", $copywrite)[6];

for ($i = 0; $i < 0x200; $i++) {
$key *= 0x805;
$key++;
$key = $key & 0xFF;
$qqwry[$i] = chr(ord($qqwry[$i]) ^ $key);
}

$qqwry = gzuncompress($qqwry);
$fp = fopen("qqwry.dat", "wb");
if ($fp) {
fwrite($fp, $qqwry);
fclose($fp);
}

8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/freshcn/qqwry

go 1.12

require (
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7
golang.org/x/text v0.3.2
)
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7 h1:gGBSHPOU7g8YjTbhwn+lvFm2VDEhhA+PwDIlstkgSxE=
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
43 changes: 26 additions & 17 deletions qqwry.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"encoding/binary"
"errors"
"io/ioutil"
"log"
"net"
Expand All @@ -17,27 +16,37 @@ var IPData fileData

// InitIPData 初始化ip库数据到内存中
func (f *fileData) InitIPData() (rs interface{}) {
var tmpData []byte

// 判断文件是否存在
_, err := os.Stat(f.FilePath)
if err != nil && os.IsNotExist(err) {
rs = errors.New("文件不存在")
return
}

// 打开文件句柄
f.Path, err = os.OpenFile(f.FilePath, os.O_RDONLY, 0400)
if err != nil {
rs = err
return
}
defer f.Path.Close()
log.Println("文件不存在,尝试从网络获取最新纯真 IP 库")
tmpData, err = GetOnline()
if err != nil {
rs = err
return
} else {
if err := ioutil.WriteFile(f.FilePath, tmpData, 0644); err == nil {
log.Printf("已将最新的纯真 IP 库保存到本地 %s ", f.FilePath)
}
}
} else {
// 打开文件句柄
log.Printf("从本地数据库文件 %s 打开\n", f.FilePath)
f.Path, err = os.OpenFile(f.FilePath, os.O_RDONLY, 0400)
if err != nil {
rs = err
return
}
defer f.Path.Close()

tmpData, err := ioutil.ReadAll(f.Path)
if err != nil {
log.Println(err)
rs = err
return
tmpData, err = ioutil.ReadAll(f.Path)
if err != nil {
log.Println(err)
rs = err
return
}
}

f.Data = tmpData
Expand Down
Binary file added screenshots.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit bb0d1d8

Please sign in to comment.