99 lines
2.9 KiB
Go
99 lines
2.9 KiB
Go
package main
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"log"
|
||
"net/http"
|
||
"strings"
|
||
)
|
||
|
||
// NameSiloAPIResponse 严格对应你提供的 JSON 返回
|
||
type NameSiloAPIResponse struct {
|
||
Request struct {
|
||
Operation string `json:"operation"`
|
||
IP string `json:"ip"`
|
||
} `json:"request"`
|
||
Reply struct {
|
||
Code int `json:"code"`
|
||
Detail string `json:"detail"`
|
||
ResourceRecords []struct {
|
||
RecordID string `json:"record_id"`
|
||
Type string `json:"type"`
|
||
Host string `json:"host"`
|
||
Value string `json:"value"`
|
||
TTL int `json:"ttl"` // JSON 中显示为数字
|
||
Distance int `json:"distance"` // JSON 中显示为数字 0
|
||
} `json:"resource_record"`
|
||
} `json:"reply"`
|
||
}
|
||
|
||
// RetrieveDNSRecords 使用 Namesilo API 获取指定域名的所有 DNS 记录
|
||
func RetrieveDNSRecords(apiKey, domain string) (*NameSiloAPIResponse, error) {
|
||
url := fmt.Sprintf("https://www.namesilo.com/api/dnsListRecords?version=1&type=json&key=%s&domain=%s", apiKey, domain)
|
||
|
||
// log.Println("Requesting URL:", url) // 调试用,如果需要隐藏 Key 请注释
|
||
|
||
resp, err := http.Get(url)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
body, err := io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var apiResponse NameSiloAPIResponse
|
||
if err := json.Unmarshal(body, &apiResponse); err != nil {
|
||
log.Printf("JSON 解析错误: %v\n原始数据: %s\n", err, string(body))
|
||
return nil, err
|
||
}
|
||
|
||
return &apiResponse, nil
|
||
}
|
||
|
||
// FetchSubdomainRecord 获取指定子域名的 DNS 记录 ID
|
||
// Subdomain 参数通常是完整域名,如 "v6.aixiao.me"
|
||
func FetchSubdomainRecord(key string, domain string, Subdomain string) string {
|
||
|
||
// 获取 DNS 记录列表
|
||
response, err := RetrieveDNSRecords(key, domain)
|
||
if err != nil {
|
||
log.Println("获取 DNS 记录网络请求失败:", err)
|
||
return "NULL"
|
||
}
|
||
|
||
// 检查 API 返回码
|
||
if response.Reply.Code != 300 {
|
||
log.Printf("NameSilo API 错误: Code %d, Detail: %s\n", response.Reply.Code, response.Reply.Detail)
|
||
return "NULL"
|
||
}
|
||
|
||
// 计算主机头 (Host Prefix)
|
||
// 如果 Subdomain 是 "v6.aixiao.me",Domain 是 "aixiao.me"
|
||
// 那么我们需要匹配的 Host 应该是 "v6"
|
||
targetHost := Subdomain
|
||
if strings.HasSuffix(Subdomain, "."+domain) {
|
||
targetHost = strings.TrimSuffix(Subdomain, "."+domain)
|
||
}
|
||
|
||
// 遍历查找
|
||
for _, record := range response.Reply.ResourceRecords {
|
||
// 1. 匹配主机名 (Host)
|
||
// 2. 匹配记录类型 (Type) 必须为 AAAA (IPv6)
|
||
if record.Host == targetHost && record.Type == "AAAA" {
|
||
log.Printf("匹配成功! RecordID: %s | Host: %s | Type: %s | Current Value: %s\n",
|
||
record.RecordID, record.Host, record.Type, record.Value)
|
||
return record.RecordID
|
||
}
|
||
}
|
||
|
||
log.Printf("未在 NameSilo 找到主机头为 [%s] 的 AAAA 记录。\n", targetHost)
|
||
log.Println("请检查 NameSilo 后台是否已手动创建了该域名的 AAAA 记录。")
|
||
|
||
return "NULL"
|
||
}
|