mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-24 02:59:16 +08:00
feat: 更换 IP 库 (#6890)
This commit is contained in:
parent
a03b131057
commit
ef793f278a
@ -1,6 +0,0 @@
|
||||
package qqwry
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed qqwry.dat
|
||||
var QQwryByte []byte
|
Binary file not shown.
@ -2,6 +2,7 @@ package v2
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/geo"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/core/app/dto"
|
||||
@ -10,7 +11,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/middleware"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/captcha"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/qqwry"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@ -175,12 +175,15 @@ func saveLoginLogs(c *gin.Context, err error) {
|
||||
logs.Status = constant.StatusSuccess
|
||||
}
|
||||
logs.IP = c.ClientIP()
|
||||
qqWry, err := qqwry.NewQQwry()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load qqwry datas failed: %s", err)
|
||||
lang := c.GetHeader("Accept-Language")
|
||||
if lang == "" {
|
||||
lang = "zh"
|
||||
}
|
||||
address, err := geo.GetIPLocation(logs.IP, lang)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("get ip location failed: %s", err)
|
||||
}
|
||||
res := qqWry.Find(logs.IP)
|
||||
logs.Agent = c.GetHeader("User-Agent")
|
||||
logs.Address = res.Area
|
||||
logs.Address = address
|
||||
_ = logService.CreateLoginLog(logs)
|
||||
}
|
||||
|
39
core/utils/geo/geo.go
Normal file
39
core/utils/geo/geo.go
Normal file
@ -0,0 +1,39 @@
|
||||
package geo
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/oschwald/maxminddb-golang"
|
||||
"net"
|
||||
"path"
|
||||
)
|
||||
|
||||
type Location struct {
|
||||
En string `maxminddb:"en"`
|
||||
Zh string `maxminddb:"zh"`
|
||||
}
|
||||
|
||||
type LocationRes struct {
|
||||
Iso string `maxminddb:"iso"`
|
||||
Country Location `maxminddb:"country"`
|
||||
Latitude float64 `maxminddb:"latitude"`
|
||||
Longitude float64 `maxminddb:"longitude"`
|
||||
Province Location `maxminddb:"province"`
|
||||
}
|
||||
|
||||
func GetIPLocation(ip, lang string) (string, error) {
|
||||
geoPath := path.Join(global.CONF.System.BaseDir, "1panel", "geo", "GeoIP.mmdb")
|
||||
reader, err := maxminddb.Open(geoPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var geoLocation LocationRes
|
||||
ipNet := net.ParseIP(ip)
|
||||
err = reader.Lookup(ipNet, &geoLocation)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if lang == "en" {
|
||||
return geoLocation.Country.En + geoLocation.Province.En, nil
|
||||
}
|
||||
return geoLocation.Country.Zh + geoLocation.Province.Zh, nil
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
package qqwry
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/cmd/server/qqwry"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
)
|
||||
|
||||
const (
|
||||
indexLen = 7
|
||||
redirectMode1 = 0x01
|
||||
redirectMode2 = 0x02
|
||||
)
|
||||
|
||||
var IpCommonDictionary []byte
|
||||
|
||||
type QQwry struct {
|
||||
Data []byte
|
||||
Offset int64
|
||||
}
|
||||
|
||||
func NewQQwry() (*QQwry, error) {
|
||||
IpCommonDictionary := qqwry.QQwryByte
|
||||
return &QQwry{Data: IpCommonDictionary}, nil
|
||||
}
|
||||
|
||||
// readData 从文件中读取数据
|
||||
func (q *QQwry) readData(num int, offset ...int64) (rs []byte) {
|
||||
if len(offset) > 0 {
|
||||
q.setOffset(offset[0])
|
||||
}
|
||||
nums := int64(num)
|
||||
end := q.Offset + nums
|
||||
dataNum := int64(len(q.Data))
|
||||
if q.Offset > dataNum {
|
||||
return nil
|
||||
}
|
||||
|
||||
if end > dataNum {
|
||||
end = dataNum
|
||||
}
|
||||
rs = q.Data[q.Offset:end]
|
||||
q.Offset = end
|
||||
return
|
||||
}
|
||||
|
||||
// setOffset 设置偏移量
|
||||
func (q *QQwry) setOffset(offset int64) {
|
||||
q.Offset = offset
|
||||
}
|
||||
|
||||
// Find ip地址查询对应归属地信息
|
||||
func (q *QQwry) Find(ip string) (res ResultQQwry) {
|
||||
res = ResultQQwry{}
|
||||
res.IP = ip
|
||||
if strings.Count(ip, ".") != 3 {
|
||||
return res
|
||||
}
|
||||
offset := q.searchIndex(binary.BigEndian.Uint32(net.ParseIP(ip).To4()))
|
||||
if offset <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var area []byte
|
||||
mode := q.readMode(offset + 4)
|
||||
if mode == redirectMode1 {
|
||||
countryOffset := q.readUInt24()
|
||||
mode = q.readMode(countryOffset)
|
||||
if mode == redirectMode2 {
|
||||
c := q.readUInt24()
|
||||
area = q.readString(c)
|
||||
} else {
|
||||
area = q.readString(countryOffset)
|
||||
}
|
||||
} else if mode == redirectMode2 {
|
||||
countryOffset := q.readUInt24()
|
||||
area = q.readString(countryOffset)
|
||||
} else {
|
||||
area = q.readString(offset + 4)
|
||||
}
|
||||
|
||||
enc := simplifiedchinese.GBK.NewDecoder()
|
||||
res.Area, _ = enc.String(string(area))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type ResultQQwry struct {
|
||||
IP string `json:"ip"`
|
||||
Area string `json:"area"`
|
||||
}
|
||||
|
||||
// readMode 获取偏移值类型
|
||||
func (q *QQwry) readMode(offset uint32) byte {
|
||||
mode := q.readData(1, int64(offset))
|
||||
return mode[0]
|
||||
}
|
||||
|
||||
// readString 获取字符串
|
||||
func (q *QQwry) readString(offset uint32) []byte {
|
||||
q.setOffset(int64(offset))
|
||||
data := make([]byte, 0, 30)
|
||||
for {
|
||||
buf := q.readData(1)
|
||||
if buf[0] == 0 {
|
||||
break
|
||||
}
|
||||
data = append(data, buf[0])
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// searchIndex 查找索引位置
|
||||
func (q *QQwry) searchIndex(ip uint32) uint32 {
|
||||
header := q.readData(8, 0)
|
||||
|
||||
start := binary.LittleEndian.Uint32(header[:4])
|
||||
end := binary.LittleEndian.Uint32(header[4:])
|
||||
|
||||
for {
|
||||
mid := q.getMiddleOffset(start, end)
|
||||
buf := q.readData(indexLen, int64(mid))
|
||||
_ip := binary.LittleEndian.Uint32(buf[:4])
|
||||
|
||||
if end-start == indexLen {
|
||||
offset := byteToUInt32(buf[4:])
|
||||
buf = q.readData(indexLen)
|
||||
if ip < binary.LittleEndian.Uint32(buf[:4]) {
|
||||
return offset
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
if _ip > ip {
|
||||
end = mid
|
||||
} else if _ip < ip {
|
||||
start = mid
|
||||
} else if _ip == ip {
|
||||
return byteToUInt32(buf[4:])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// readUInt24
|
||||
func (q *QQwry) readUInt24() uint32 {
|
||||
buf := q.readData(3)
|
||||
return byteToUInt32(buf)
|
||||
}
|
||||
|
||||
// getMiddleOffset
|
||||
func (q *QQwry) getMiddleOffset(start uint32, end uint32) uint32 {
|
||||
records := ((end - start) / indexLen) >> 1
|
||||
return start + records*indexLen
|
||||
}
|
||||
|
||||
// byteToUInt32 将 byte 转换为uint32
|
||||
func byteToUInt32(data []byte) uint32 {
|
||||
i := uint32(data[0]) & 0xff
|
||||
i |= (uint32(data[1]) << 8) & 0xff00
|
||||
i |= (uint32(data[2]) << 16) & 0xff0000
|
||||
return i
|
||||
}
|
1
go.mod
1
go.mod
@ -99,6 +99,7 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mozillazg/go-httpheader v0.2.1 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rs/xid v1.5.0 // indirect
|
||||
|
2
go.sum
2
go.sum
@ -300,6 +300,8 @@ github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISe
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
|
Loading…
Reference in New Issue
Block a user