Initial commit

This commit is contained in:
2026-06-30 15:14:37 +08:00
commit 15dab96872
311 changed files with 95639 additions and 0 deletions
+164
View File
@@ -0,0 +1,164 @@
package service
import (
"context"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"strings"
"time"
)
// IPDetectionService IP 检测服务
type IPDetectionService struct {
httpClient *http.Client
}
// NewIPDetectionService 创建 IP 检测服务
func NewIPDetectionService() *IPDetectionService {
return &IPDetectionService{
httpClient: &http.Client{
Timeout: 10 * time.Second,
},
}
}
// GetPublicIPv4 获取公网 IPv4 地址
func (s *IPDetectionService) GetPublicIPv4() (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.ipify.org?format=json", nil)
if err != nil {
return "", fmt.Errorf("创建请求失败:%w", err)
}
resp, err := s.httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("请求失败:%w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取响应失败:%w", err)
}
var result struct {
IP string `json:"ip"`
}
if err := json.Unmarshal(body, &result); err != nil {
return "", fmt.Errorf("解析 JSON 失败:%w", err)
}
if result.IP == "" {
return "", fmt.Errorf("未获取到 IPv4 地址")
}
return result.IP, nil
}
// GetPublicIPv6 获取公网 IPv6 地址
func (s *IPDetectionService) GetPublicIPv6() (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", "https://api64.ipify.org?format=json", nil)
if err != nil {
return "", fmt.Errorf("创建请求失败:%w", err)
}
resp, err := s.httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("请求失败:%w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取响应失败:%w", err)
}
var result struct {
IP string `json:"ip"`
}
if err := json.Unmarshal(body, &result); err != nil {
return "", fmt.Errorf("解析 JSON 失败:%w", err)
}
if result.IP == "" {
return "", fmt.Errorf("未获取到 IPv6 地址")
}
// 检查是否是 IPv6 地址(包含冒号)
if !strings.Contains(result.IP, ":") {
return "", fmt.Errorf("获取到的不是有效的 IPv6 地址:%s", result.IP)
}
return result.IP, nil
}
// GetLocalIPv4 获取本地 IPv4 地址(第一个非回环接口)
func (s *IPDetectionService) GetLocalIPv4() (string, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return "", fmt.Errorf("获取网络接口失败:%w", err)
}
for _, addr := range addrs {
// 检查是否为 IP 地址且为 IPv4
if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
return ipNet.IP.String(), nil
}
}
}
return "", fmt.Errorf("未找到 IPv4 地址")
}
// GetLocalIPv6 获取本地 IPv6 地址(第一个非回环接口)
func (s *IPDetectionService) GetLocalIPv6() (string, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return "", fmt.Errorf("获取网络接口失败:%w", err)
}
for _, addr := range addrs {
if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() == nil && ipNet.IP.To16() != nil {
return ipNet.IP.String(), nil
}
}
}
return "", fmt.Errorf("未找到 IPv6 地址")
}
// DetectIP 检测 IP 地址(根据记录类型返回对应的 IP)
func (s *IPDetectionService) DetectIP(recordType string) (string, error) {
switch recordType {
case "A":
// A 记录优先使用公网 IPv4
ip, err := s.GetPublicIPv4()
if err != nil {
// 降级到本地 IPv4
return s.GetLocalIPv4()
}
return ip, nil
case "AAAA":
// AAAA 记录优先使用公网 IPv6
ip, err := s.GetPublicIPv6()
if err != nil {
// 降级到本地 IPv6
return s.GetLocalIPv6()
}
return ip, nil
default:
return "", fmt.Errorf("不支持的记录类型:%s", recordType)
}
}