235 lines
5.5 KiB
Go
Raw Normal View History

2025-02-05 10:53:26 +08:00
package main
import (
"context"
"flag"
"fmt"
2025-02-07 16:39:02 +08:00
"log"
2025-02-05 10:53:26 +08:00
"net"
"os"
2025-02-05 10:53:26 +08:00
"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 {
2025-02-07 16:39:02 +08:00
log.Printf("获取 IPv6 地址失败: %v\n", err)
2025-02-05 10:53:26 +08:00
return "NULL"
}
//fmt.Println("IPv6 地址列表:")
for iface, ips := range addresses {
2025-02-07 16:39:02 +08:00
//log.Printf("Interface: %s\n", iface)
2025-02-05 10:53:26 +08:00
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) {
2025-02-05 10:53:26 +08:00
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)
2025-02-05 10:53:26 +08:00
if Now_ipv6_addr != Domain_ipv6_addr {
2025-02-07 16:39:02 +08:00
log.Printf("域名解析地址: %s\n", Domain_ipv6_addr)
log.Printf("当前地址: %s\n", Now_ipv6_addr)
log.Printf("域名解析地址与现在地址不相等!!!\n")
2025-02-05 10:53:26 +08:00
RecordID := FetchSubdomainRecord(*info._Key, *info._Domain, *info._Subdomain)
2025-02-07 16:39:02 +08:00
log.Printf("RecordID:%s\n", RecordID)
2025-02-05 10:53:26 +08:00
if RecordID != "NULL" {
rrid := RecordID
rrhost := strings.Split(*info._Subdomain, ".")[0] // 获取子域名前缀 v6
2025-02-05 10:53:26 +08:00
rrvalue := Now_ipv6_addr
r := ProcessDNSUpdateForDomain(*info._Key, *info._Domain, rrid, rrhost, rrvalue)
2025-02-05 10:53:26 +08:00
if r == 1 {
}
}
} else {
2025-02-07 16:39:02 +08:00
log.Printf("域名解析地址: %s\n", Domain_ipv6_addr)
log.Printf("当前地址: %s\n", Now_ipv6_addr)
log.Printf("域名解析地址与现在地址相等,无需处理!!!\n")
2025-02-05 10:53:26 +08:00
}
}
// 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
}
2025-02-05 10:53:26 +08:00
func main() {
2025-02-05 10:53:26 +08:00
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 密钥")
2025-02-05 10:53:26 +08:00
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)
2025-02-05 10:53:26 +08:00
// 守护进程模式
if *daemon {
Daemon()
}
//TimeZone()
2025-02-05 10:53:26 +08:00
for {
Loop(info)
Sleep(30)
2025-02-05 10:53:26 +08:00
}
}