package main import ( "context" "flag" "fmt" "log" "net" "os" "strings" "time" ) // 判断IPv6 地址类型 func classifyIPv6(ip net.IP) string { if ip.IsLoopback() { return "Loopback" } else if ip.IsLinkLocalUnicast() { return "Link-Local" } else if ip.IsGlobalUnicast() { return "Global" } return "Unknown" } // getIPv6Addresses 获取网络接口的 IPv6 地址。 // 它会跳过回环接口,并且只考虑已启用的接口。 func getIPv6Addresses() (map[string][]net.IP, error) { // 创建一个 map 用于存储接口名称及其对应的 IPv6 地址。 addresses := make(map[string][]net.IP) // 获取系统上的所有网络接口。 interfaces, err := net.Interfaces() if err != nil { return nil, err // 如果无法获取接口信息,则返回错误。 } // 遍历所有网络接口。 for _, iface := range interfaces { // 跳过未启用的接口或回环接口。 if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 { continue } // 获取与该接口关联的地址。 addrs, err := iface.Addrs() if err != nil { return nil, err // 如果无法获取地址,则返回错误。 } // 遍历该接口的所有地址。 for _, addr := range addrs { var ip net.IP switch v := addr.(type) { case *net.IPNet: ip = v.IP // 从 IPNet 类型中提取 IP。 case *net.IPAddr: ip = v.IP // 从 IPAddr 类型中提取 IP。 } // 检查 IP 是否为 IPv6 地址(即不是 IPv4)。 if ip != nil && ip.To4() == nil { // 将 IPv6 地址添加到对应的接口名称列表中。 addresses[iface.Name] = append(addresses[iface.Name], ip) } } } return addresses, nil // 返回包含 IPv6 地址的映射。 } // 获取指定接口的 IPv6 地址 func pppoe_interface_ipv6(_interface string) string { addresses, err := getIPv6Addresses() if err != nil { log.Printf("获取 IPv6 地址失败: %v\n", err) return "NULL" } //fmt.Println("IPv6 地址列表:") for iface, ips := range addresses { //log.Printf("Interface: %s\n", iface) if iface == _interface { for _, ip := range ips { addrType := classifyIPv6(ip) if addrType == "Global" { return ip.String() } } } } return "NULL" } // 使用指定的 DNS 服务器解析域名的 IPv6 地址 func check_domain_ipv6(domain string) string { // 自定义解析器,使用 8.8.8.8 作为 DNS 服务器 resolver := &net.Resolver{ PreferGo: true, Dial: func(ctx context.Context, network, address string) (net.Conn, error) { d := net.Dialer{ Timeout: time.Second * 5, } return d.DialContext(ctx, "udp", "8.8.8.8:53") // 指定 Google DNS }, } // 查询域名的 IP 地址 ips, err := resolver.LookupIP(context.Background(), "ip6", domain) if err != nil { return "NULL" } // 遍历返回的 IP 地址,返回第一个 IPv6 地址 for _, ip := range ips { if ip.To4() == nil { return ip.String() } } return "NULL" } // 循环获取域名解析地址和当前地址,并判断是否需要更新域名解析地址 func Loop(info INFO) { var Domain_ipv6_addr string var Now_ipv6_addr string Domain_ipv6_addr = check_domain_ipv6(*info._Subdomain) Now_ipv6_addr = pppoe_interface_ipv6(*info._interface) if Now_ipv6_addr != Domain_ipv6_addr { log.Printf("域名解析地址: %s\n", Domain_ipv6_addr) log.Printf("当前地址: %s\n", Now_ipv6_addr) log.Printf("域名解析地址与现在地址不相等!!!\n") RecordID := FetchSubdomainRecord(*info._Key, *info._Domain, *info._Subdomain) log.Printf("RecordID:%s\n", RecordID) if RecordID != "NULL" { rrid := RecordID rrhost := strings.Split(*info._Subdomain, ".")[0] // 获取子域名前缀 v6 rrvalue := Now_ipv6_addr r := ProcessDNSUpdateForDomain(*info._Key, *info._Domain, rrid, rrhost, rrvalue) if r == 1 { } } } else { log.Printf("域名解析地址: %s\n", Domain_ipv6_addr) log.Printf("当前地址: %s\n", Now_ipv6_addr) log.Printf("域名解析地址与现在地址相等,无需处理!!!\n") } } // Sleep 函数 func Sleep(m int) { time.Sleep(time.Duration(m) * time.Minute) } func TimeZone() { // 设置 Go 的本地时区为 Asia/Shanghai loc, err := time.LoadLocation("Asia/Shanghai") if err != nil { log.Fatalf("加载时区失败: %v", err) } time.Local = loc } type INFO struct { _interface *string _Domain *string _Subdomain *string _Key *string } func GetDaemon(_Subdomain *string) *string { // 使用 strings.Split 分割域名 parts := strings.Split(*_Subdomain, ".") // 检查分割后的部分数量 if len(parts) < 2 { fmt.Println("无效的域名") return nil } // 获取主域名 mainDomain := parts[len(parts)-2] + "." + parts[len(parts)-1] return &mainDomain } func main() { daemon := flag.Bool("d", false, "守护进程模式") _interface := flag.String("i", "pppoe-wan", "网卡") _Subdomain := flag.String("s", "v6.aixiao.me", "子域名") _key := flag.String("k", "NULL", "NameSilo API 密钥") flag.Parse() var info INFO info._interface = _interface info._Subdomain = _Subdomain info._Key = _key info._Domain = GetDaemon(_Subdomain) if *info._Key == "NULL" { envKey := os.Getenv("NAMESILO") if envKey != "" { info._Key = &envKey // 将环境变量的值赋值给 info._Key } else { log.Fatalf("密钥未设置,请通过 -k 参数或 NAMESILO 环境变量提供密钥") } } fmt.Println("主域名:", *info._Domain) fmt.Println("子域名:", *info._Subdomain) fmt.Println("密钥:", *info._Key) // 守护进程模式 if *daemon { Daemon() } //TimeZone() for { Loop(info) Sleep(15) } }