feat(rpc): 设置默认RPC地址为本地回环

修复RPC客户端连接问题,将默认服务器地址设置为127.0.0.1以确保本地连接正常

refactor(qqwry): 优化IP地址查询功能

移除不必要的正则表达式依赖,重构IP地址查询逻辑,提高代码性能和可维护性

fix(server): 保存确定的端口到配置中

确保服务器端口在确定后正确保存到配置中,避免端口配置丢失
This commit is contained in:
2026-01-08 05:15:10 +08:00
parent 56fe334045
commit 4d0464c76b
8 changed files with 116 additions and 164 deletions

View File

@@ -12,12 +12,9 @@ import (
"net/http"
"net/url"
"os"
"regexp"
"strings"
"sync"
_ "embed"
"github.com/ipipdotnet/ipdb-go"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
@@ -88,143 +85,6 @@ func QueryIP(ip string) (location *Location, err error) {
}
}
// GetIpAddress 获取 IP 归属地和运营商
func GetIpAddress(ip string) (string, error) {
html, err := doGet("https://www.ipshudi.com/" + ip + "/")
if err != nil {
return "", err
}
div := getAddress(html, `<td>\n<span>.*</span>\n`)
div1 := getAddress(html, `<td class="th">运营商</td><td><span>.*</span>`)
location := "未知归属地"
if div != "" {
location = strings.Split(div, "<span>")[1]
location = strings.Split(location, "</span>")[0]
}
isp := ""
if div1 != "" {
isp = strings.Split(div1, "<span>")[1]
isp = strings.Split(isp, "</span>")[0]
}
return location + " " + isp, nil
}
// 定义响应数据结构(与 API 返回字段对应)
type IPLocationResponse struct {
IP string `json:"ip"`
IPNumber string `json:"ip_number"`
IPVersion int `json:"ip_version"`
CountryName string `json:"country_name"`
CountryCode2 string `json:"country_code2"`
ISP string `json:"isp"`
ResponseCode string `json:"response_code"`
ResponseMessage string `json:"response_message"`
}
// 调用 IP 定位 API
func LookupIP(ip string, format string) (*IPLocationResponse, error) {
// 构建请求 URL
baseURL := "https://api.iplocation.net/"
params := url.Values{}
params.Add("ip", ip)
if format != "" {
params.Add("format", format)
}
fullURL := baseURL + "?" + params.Encode()
// 发送 GET 请求
resp, err := http.Get(fullURL)
if err != nil {
return nil, fmt.Errorf("请求失败: %v", err)
}
defer resp.Body.Close()
// 读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败: %v", err)
}
// 解析 JSON 响应(默认格式为 json
var result IPLocationResponse
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("解析响应失败: %v (响应内容: %s)", err, string(body))
}
// 检查 API 响应状态
if result.ResponseCode != "200" {
return nil, fmt.Errorf("API 调用失败: %s (%s)", result.ResponseMessage, result.ResponseCode)
}
return &result, nil
}
// doGet 发送 HTTP GET 请求,返回响应内容
func doGet(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
// getAddress 使用正则表达式从 HTML 中提取内容
func getAddress(html []byte, pattern string) string {
re := regexp.MustCompile(pattern)
return re.FindString(string(html))
}
// 判断IP是否为私有地址包括IPv4和IPv6
func isPrivateIP(ipStr string) (bool, error) {
ip := net.ParseIP(ipStr)
if ip == nil {
return false, fmt.Errorf("无效的IP地址: %s", ipStr)
}
// 定义私有网段
privateNets := []string{
// IPv4私有网段
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
// IPv6私有网段ULA和链路本地
"fc00::/7",
"fe80::/10",
}
// 检查IP是否属于任一私有网段
for _, cidr := range privateNets {
_, netIP, err := net.ParseCIDR(cidr)
if err != nil {
return false, err
}
if netIP.Contains(ip) {
return true, nil
}
}
return false, nil
}
// 判断IP是否为环回地址
func isLoopbackIP(ipStr string) (bool, error) {
ip := net.ParseIP(ipStr)
if ip == nil {
return false, fmt.Errorf("无效的IP地址: %s", ipStr)
}
return ip.IsLoopback(), nil
}
// QueryIPDat 从dat查询IP仅加载dat格式数据库时使用
func QueryIPDat(ipv4 string) (location *Location, err error) {
ip := net.ParseIP(ipv4).To4()
@@ -232,11 +92,24 @@ func QueryIPDat(ipv4 string) (location *Location, err error) {
return nil, errors.New("ip is not ipv4")
}
if isLoopback, err := isLoopbackIP(ipv4); isLoopback || err != nil {
if ip.IsLoopback() {
return &Location{ISP: "局域网", IP: ipv4}, nil
}
if isPrivateIP, err := isPrivateIP(ipv4); isPrivateIP || err != nil {
return &Location{ISP: "私有地址", IP: ipv4}, nil
privateNets := []string{
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
}
for _, cidr := range privateNets {
_, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
continue
}
if ipnet.Contains(ip) {
return &Location{ISP: "私有地址", IP: ipv4}, nil
}
}
ip32 := binary.BigEndian.Uint32(ip)
posA := binary.LittleEndian.Uint32(data[:4])
@@ -245,16 +118,19 @@ func QueryIPDat(ipv4 string) (location *Location, err error) {
for {
mid := posA + (((posZ-posA)/indexLen)>>1)*indexLen
if int(mid+indexLen) > len(data) {
// 当数据中找不到IP时尝试使用网络查询
r, _ := LookupIP(ipv4, "json")
if r != nil {
location := &Location{ISP: r.ISP, IP: r.IP, Country: r.CountryName, District: r.CountryCode2}
location := &Location{
IP: r.IP,
Country: r.CountryName,
ISP: r.ISP,
}
locationCache.Store(ipv4, location)
return location, nil
} else {
return nil, errors.New("ip not found")
}
}
buf := data[mid : mid+indexLen]
_ip := binary.LittleEndian.Uint32(buf[:4])
@@ -360,6 +236,56 @@ func QueryIPIpdb(ip string) (location *Location, err error) {
locationCache.Store(ip, location)
return location, nil
}
// IPLocationResponse 定义IP定位API的响应结构
type IPLocationResponse struct {
IP string `json:"ip"`
IPNumber string `json:"ip_number"`
IPVersion int `json:"ip_version"`
CountryName string `json:"country_name"`
CountryCode2 string `json:"country_code2"`
ISP string `json:"isp"`
ResponseCode string `json:"response_code"`
ResponseMessage string `json:"response_message"`
}
// LookupIP 调用外部API查询IP地理位置
func LookupIP(ip string, format string) (*IPLocationResponse, error) {
// 构建请求 URL
baseURL := "https://api.iplocation.net/"
params := url.Values{}
params.Add("ip", ip)
if format != "" {
params.Add("format", format)
}
fullURL := baseURL + "?" + params.Encode()
// 发送 GET 请求
resp, err := http.Get(fullURL)
if err != nil {
return nil, fmt.Errorf("请求失败: %v", err)
}
defer resp.Body.Close()
// 读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败: %v", err)
}
// 解析 JSON 响应
var result IPLocationResponse
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("解析响应失败: %v (响应内容: %s)", err, string(body))
}
// 检查 API 响应状态
if result.ResponseCode != "200" {
return nil, fmt.Errorf("API 调用失败: %s (%s)", result.ResponseMessage, result.ResponseCode)
}
return &result, nil
}
// LoadData 从内存加载IP数据库
func LoadData(database []byte) {
@@ -407,3 +333,4 @@ func SplitResult(addr string, isp string, ipv4 string) (location *Location) {
}
return
}