release: v0.1.0

This commit is contained in:
LC mac
2026-01-13 23:55:58 +08:00
parent d60c89201f
commit 9c252cf92c
6 changed files with 381 additions and 127 deletions

70
main.go
View File

@@ -25,6 +25,7 @@ type Config struct {
Cloudflare struct {
APIToken string `yaml:"api_token"`
ZoneID string `yaml:"zone_id"`
ZoneName string `yaml:"zone_name"` // <- add this
Subdomains []struct {
Name string `yaml:"name"`
Proxied bool `yaml:"proxied"`
@@ -54,11 +55,16 @@ type CloudflareDNSRecord struct {
TTL int `json:"ttl"`
}
// CloudflareResponse is the generic API response structure
type CloudflareError struct {
Code int `json:"code"`
Message string `json:"message"`
}
type CloudflareResponse[T any] struct {
Success bool `json:"success"`
Errors []string `json:"errors"`
Result T `json:"result"`
Success bool `json:"success"`
Errors []CloudflareError `json:"errors"` // ← was `string`, now `[]CloudflareError`
Messages []string `json:"messages"`
Result T `json:"result"`
}
// DNSUpdater manages the DDNS update process
@@ -71,8 +77,14 @@ type DNSUpdater struct {
func main() {
configPath := flag.String("config", "config.yaml", "path to config file")
initConfig := flag.Bool("init-config", false, "print example config to stdout")
flag.Parse()
if *initConfig {
printConfigTemplate()
return
}
// Load configuration
config, err := loadConfig(*configPath)
if err != nil {
@@ -111,6 +123,37 @@ func main() {
logger.Info("DDNS Updater stopped gracefully")
}
func printConfigTemplate() {
tmpl := `# Check interval in minutes (5, 15, or 30)
check_interval: 5
cloudflare:
api_token: "your-api-token-here"
zone_id: "your-zone-id-here"
zone_name: "example.com"
subdomains:
- name: "lc"
proxied: false
- name: "git"
proxied: false
- name: "mempool"
proxied: false
logging:
file: "ddns-updater.log"
level: "info"
retry:
max_attempts: 3
delay_seconds: 5
webhook:
enabled: false
url: ""
`
fmt.Print(tmpl)
}
// loadConfig reads and parses the YAML configuration file
func loadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
@@ -201,6 +244,13 @@ func (u *DNSUpdater) run(ctx context.Context) {
}
}
func (u *DNSUpdater) fqdn(subdomain string) string {
if subdomain == "@" || subdomain == "" {
return u.config.Cloudflare.ZoneName // root record
}
return subdomain + "." + u.config.Cloudflare.ZoneName
}
// updateDNS checks current IP and updates DNS records if needed
func (u *DNSUpdater) updateDNS(ctx context.Context) error {
// Get current public IP
@@ -334,9 +384,11 @@ func (u *DNSUpdater) updateSubdomainAttempt(ctx context.Context, subdomain, ip s
url := fmt.Sprintf("https://api.cloudflare.com/client/v4/zones/%s/dns_records/%s",
u.config.Cloudflare.ZoneID, recordID)
name := u.fqdn(subdomain)
payload := map[string]any{
"type": "A",
"name": subdomain,
"name": name,
"content": ip,
"proxied": proxied,
"ttl": 300,
@@ -380,8 +432,12 @@ func (u *DNSUpdater) updateSubdomainAttempt(ctx context.Context, subdomain, ip s
// getDNSRecord retrieves the record ID and current IP for a subdomain
func (u *DNSUpdater) getDNSRecord(ctx context.Context, subdomain string) (recordID, currentIP string, err error) {
url := fmt.Sprintf("https://api.cloudflare.com/client/v4/zones/%s/dns_records?type=A&name=%s",
u.config.Cloudflare.ZoneID, subdomain)
name := u.fqdn(subdomain)
url := fmt.Sprintf(
"https://api.cloudflare.com/client/v4/zones/%s/dns_records?type=A&name=%s",
u.config.Cloudflare.ZoneID,
name,
)
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {