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