release: v0.1.0
This commit is contained in:
70
main.go
70
main.go
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user