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 +}