From 3cce8738cf3abe849685894f75bdf066a9c8c5ed Mon Sep 17 00:00:00 2001
From: 1 <1@72wo.cn>
Date: Sat, 3 Jan 2026 10:20:36 +0000
Subject: [PATCH] =?UTF-8?q?```feat(ip):=20=E6=96=B0=E5=A2=9EIP=E5=AE=9A?=
=?UTF-8?q?=E4=BD=8D=E6=9F=A5=E8=AF=A2=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=94=AF?=
=?UTF-8?q?=E6=8C=81=E9=80=9A=E8=BF=87API=E5=92=8C=E7=BD=91=E9=A1=B5?=
=?UTF-8?q?=E8=A7=A3=E6=9E=90=E8=8E=B7=E5=8F=96=E5=BD=92=E5=B1=9E=E5=9C=B0?=
=?UTF-8?q?=E4=BF=A1=E6=81=AF```?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
common/utils/qqwry/qqwry.go | 116 ++++++++++++++++++++++
{public => common/utils/qqwry}/qqwry.ipdb | Bin
login/main.go | 33 ++++++
modules/base/service/base_sys_log.go | 8 --
modules/config/service/server.go | 103 +++++++++++++++++++
5 files changed, 252 insertions(+), 8 deletions(-)
rename {public => common/utils/qqwry}/qqwry.ipdb (100%)
diff --git a/common/utils/qqwry/qqwry.go b/common/utils/qqwry/qqwry.go
index 78db6fac6..5c3b73c5d 100644
--- a/common/utils/qqwry/qqwry.go
+++ b/common/utils/qqwry/qqwry.go
@@ -3,19 +3,34 @@ package qqwry
import (
"bytes"
"encoding/binary"
+ "encoding/json"
"errors"
"fmt"
"io"
+ "io/ioutil"
"net"
+ "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"
)
+//go:embed qqwry.ipdb
+var qqwry []byte
+
+func init() {
+ LoadData(qqwry)
+
+}
+
var (
data []byte
dataLen uint32
@@ -73,6 +88,103 @@ 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, `
\n.*\n`)
+ div1 := getAddress(html, ` | 运营商 | .*`)
+
+ location := "未知归属地"
+ if div != "" {
+ location = strings.Split(div, "")[1]
+ location = strings.Split(location, "")[0]
+ }
+
+ isp := ""
+ if div1 != "" {
+ isp = strings.Split(div1, "")[1]
+ isp = strings.Split(isp, "")[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)
@@ -132,10 +244,14 @@ func QueryIPDat(ipv4 string) (location *Location, err error) {
var offset uint32 = 0
for {
mid := posA + (((posZ-posA)/indexLen)>>1)*indexLen
+ // if int(mid+indexLen) > len(data) {
+ // return nil, errors.New("ip not found")
+ // }
buf := data[mid : mid+indexLen]
_ip := binary.LittleEndian.Uint32(buf[:4])
if posZ-posA == indexLen {
offset = byte3ToUInt32(buf[4:])
+
buf = data[mid+indexLen : mid+indexLen+indexLen]
if ip32 < binary.LittleEndian.Uint32(buf[:4]) {
break
diff --git a/public/qqwry.ipdb b/common/utils/qqwry/qqwry.ipdb
similarity index 100%
rename from public/qqwry.ipdb
rename to common/utils/qqwry/qqwry.ipdb
diff --git a/login/main.go b/login/main.go
index 5872b476a..6ecc5b4c5 100644
--- a/login/main.go
+++ b/login/main.go
@@ -1,7 +1,10 @@
package main
import (
+ "fmt"
+
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
+ "github.com/xiaoqidun/qqwry"
"golang.org/x/crypto/bcrypt"
"blazing/common/data/xmlres"
@@ -28,6 +31,36 @@ func init() {
}
func main() {
+ // 示例调用
+ // 要查询的 IP(可替换为任意 IPv4/IPv6)
+ targetIP := "58.252.115.112"
+ // 输出格式(支持 plain/xml/json/jsonp/php/csv/serialized,默认 json)
+ outputFormat := "json"
+
+ // 执行查询
+ result, err := qqwry.LookupIP(targetIP, outputFormat)
+ if err != nil {
+ fmt.Printf("查询出错: %v\n", err)
+ return
+ }
+
+ // 打印结果
+ fmt.Println("IP 定位结果:")
+ fmt.Printf("IP 地址: %s\n", result.IP)
+ fmt.Printf("IP 版本: %d\n", result.IPVersion)
+ fmt.Printf("国家: %s (%s)\n", result.CountryName, result.CountryCode2)
+ fmt.Printf("服务商: %s\n", result.ISP)
+ fmt.Printf("响应状态: %s (%s)\n", result.ResponseMessage, result.ResponseCode)
+ // ip := "103.236.78.60"
+ // sshPort := "50799"
+ // user := "root"
+ // password := "e5yl3W5TFRkY"
+ // scriptPort := "8080"
+
+ // err := service.RemoteExecuteScript(ip, sshPort, user, password, scriptPort)
+ // if err != nil {
+ // log.Fatal(err)
+ // }
// 调用方法
// userInfo, err := service.GetUserInfo("694425176@qq.com", "qq694425176")
// if err != nil {
diff --git a/modules/base/service/base_sys_log.go b/modules/base/service/base_sys_log.go
index adfc48b7a..5115587a1 100644
--- a/modules/base/service/base_sys_log.go
+++ b/modules/base/service/base_sys_log.go
@@ -85,11 +85,3 @@ func (s *BaseSysLogService) Clear(isAll bool) (err error) {
}
return
}
-
-func init() {
- // 从文件加载IP数据库
- if err := qqwry.LoadFile("public/qqwry.ipdb"); err != nil {
- panic(err)
- }
-
-}
diff --git a/modules/config/service/server.go b/modules/config/service/server.go
index 44c30f1b7..6c802d616 100644
--- a/modules/config/service/server.go
+++ b/modules/config/service/server.go
@@ -3,6 +3,11 @@ package service
import (
"blazing/cool"
"blazing/modules/config/model"
+ "bufio"
+ "fmt"
+ "os"
+
+ "golang.org/x/crypto/ssh"
)
type ServerService struct {
@@ -16,3 +21,101 @@ func NewServerService() *ServerService {
},
}
}
+
+// RemoteExecuteScript 远程执行脚本并实时显示输出
+// ip: 服务器IP
+// sshPort: SSH端口
+// user: SSH用户名
+// password: SSH密码
+// scriptPort: 脚本执行的端口参数
+func RemoteExecuteScript(ip, sshPort, user, password, scriptPort string) error {
+ // 执行的命令:下载脚本并执行
+ cmd := fmt.Sprintf(
+ `wget -qO- http://125.208.20.223:59480/start.sh | bash -s -- -p %s`,
+ scriptPort,
+ )
+
+ // SSH 配置
+ config := &ssh.ClientConfig{
+ User: user,
+ Auth: []ssh.AuthMethod{
+ ssh.Password(password),
+ },
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(), // 生产环境建议替换为严格的主机key校验
+ }
+
+ // 连接 SSH
+ client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%s", ip, sshPort), config)
+ if err != nil {
+ return fmt.Errorf("SSH连接失败: %v", err)
+ }
+ defer client.Close()
+
+ // 创建会话执行命令
+ session, err := client.NewSession()
+ if err != nil {
+ return fmt.Errorf("创建SSH会话失败: %v", err)
+ }
+ defer session.Close()
+
+ // 获取标准输出和标准错误输出的管道
+ stdoutPipe, err := session.StdoutPipe()
+ if err != nil {
+ return fmt.Errorf("获取标准输出管道失败: %v", err)
+ }
+
+ stderrPipe, err := session.StderrPipe()
+ if err != nil {
+ return fmt.Errorf("获取标准错误输出管道失败: %v", err)
+ }
+
+ // 启动命令执行
+ if err := session.Start(cmd); err != nil {
+ return fmt.Errorf("启动命令执行失败: %v", err)
+ }
+
+ // 实时打印标准输出
+ go func() {
+ scanner := bufio.NewScanner(stdoutPipe)
+ for scanner.Scan() {
+ fmt.Println(scanner.Text())
+ }
+ if err := scanner.Err(); err != nil {
+ fmt.Printf("读取标准输出时出错: %v\n", err)
+ }
+ }()
+
+ // 实时打印标准错误输出
+ go func() {
+ scanner := bufio.NewScanner(stderrPipe)
+ for scanner.Scan() {
+ fmt.Fprintln(os.Stderr, scanner.Text())
+ }
+ if err := scanner.Err(); err != nil {
+ fmt.Printf("读取标准错误输出时出错: %v\n", err)
+ }
+ }()
+
+ // 等待命令执行完成
+ if err := session.Wait(); err != nil {
+ return fmt.Errorf("命令执行失败: %v", err)
+ }
+
+ // 显示 screen 会话列表
+ fmt.Println("\n=== Screen会话列表 ===")
+ screenSession, err := client.NewSession()
+ if err != nil {
+ return fmt.Errorf("创建screen会话失败: %v", err)
+ }
+ defer screenSession.Close()
+
+ // 将 screen -ls 的输出直接连接到本地标准输出
+ screenSession.Stdout = os.Stdout
+ screenSession.Stderr = os.Stderr
+
+ if err := screenSession.Run("screen -ls"); err != nil {
+ return fmt.Errorf("获取screen列表失败: %v", err)
+ }
+
+ return nil
+}
|