package main import ( "context" "log" "net" "os/signal" "syscall" "time" "github.com/mkelcik/cloudflare-ddns-update/internal" "github.com/mkelcik/cloudflare-ddns-update/internal/dns_providers" "github.com/mkelcik/cloudflare-ddns-update/internal/dns_resolver" "github.com/mkelcik/cloudflare-ddns-update/notifications" "github.com/mkelcik/cloudflare-ddns-update/public_resolvers" ) type PublicIpResolver interface { ResolvePublicIp(ctx context.Context) (net.IP, error) } func getResolver(resolverName string) (PublicIpResolver, string) { switch resolverName { // HERE add another resolver if needed case public_resolvers.CloudflareTraceTag: return public_resolvers.NewDefaultCloudflareTrace(), public_resolvers.CloudflareTraceTag case public_resolvers.V4IdentMeTag: return public_resolvers.NewV4IdentMeDefault(), public_resolvers.V4IdentMeTag case public_resolvers.IcanhazipTag: return public_resolvers.NewIcanhazipDefault(), public_resolvers.IcanhazipTag case public_resolvers.IfConfigMeTag: fallthrough default: return public_resolvers.NewDefaultIfConfigMe(), public_resolvers.IfConfigMeTag } } func getProvider(ctx context.Context, config internal.Config) (dns_providers.DNSProvider, string) { switch config.DNSProviderTag { case dns_providers.DirectadminTag: return dns_providers.NewDirectAdminProvider(ctx, config), dns_providers.DirectadminTag case dns_providers.CloudflareTag: fallthrough default: return dns_providers.NewCloudflareProvider(ctx, config), dns_providers.CloudflareTag } } func main() { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() config := internal.NewConfig() if err := config.Validate(); err != nil { log.Fatalln(err) } notifiers := notifications.GetNotifiers(config.Notifiers) // public ip resolver publicIpResolver, resolverTag := getResolver(config.PublicIpResolverTag) dnsProvider, providerTag := getProvider(ctx, config) log.Printf("Using DNS Provider %s", providerTag) checkFunc := func() { currentPublicIP, err := publicIpResolver.ResolvePublicIp(ctx) if err != nil { log.Fatal(err) } log.Printf("Current public ip `%s` (resolver: %s)", currentPublicIP, resolverTag) if err != nil { log.Fatal(err) } for _, dnsRecord := range config.DnsRecordsToCheck { current_dns_record := dns_resolver.ResolveHostname(dnsRecord, "1.1.1.1") log.Printf("Checking record `%s` with current value `%s` ...", dnsRecord, current_dns_record.String()) if currentPublicIP.String() == current_dns_record.String() { log.Println("OK") continue // no update needed } if err := dnsProvider.UpdateRecord(dnsRecord, currentPublicIP.String(), current_dns_record.String()); err != nil { log.Printf("error updating dns record: %s", err) continue } if err := notifiers.NotifyWithLog(ctx, notifications.Notification{ OldIp: net.ParseIP(string(current_dns_record)), NewIp: currentPublicIP, CheckedAt: time.Now(), ResolverTag: resolverTag, Domain: dnsRecord, WebhookToken: config.WebhookToken, }); err != nil { log.Printf("errors in notifications: %s", err) } log.Printf("Updated to `%s`", currentPublicIP) } } log.Printf("checking ...") checkFunc() log.Println("waiting for check tick ...") ticker := time.NewTicker(config.CheckInterval) defer ticker.Stop() for { select { case <-ticker.C: log.Println("tick received checking ...") checkFunc() case <-ctx.Done(): break } } }