Initial commit
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user