package app import ( "context" "fmt" "time" "git.ext.icikowski.pl/icikowski/ip-ddns/adapter/directadmin" "git.ext.icikowski.pl/icikowski/ip-ddns/adapter/dnsresolver" "git.ext.icikowski.pl/icikowski/ip-ddns/config" "github.com/rs/zerolog" ) type Service struct { da directadmin.DirectAdminClient resolv dnsresolver.DomainNameResolver srcDomain string srcNameserver string dstDomain string dstNameserver string entryDomain string entryName string entryTTL uint16 resyncTime time.Duration log zerolog.Logger } func NewService( directadminClient directadmin.DirectAdminClient, dnsResolver dnsresolver.DomainNameResolver, domainConfig config.DomainConfig, resyncTime time.Duration, log zerolog.Logger, ) *Service { return &Service{ da: directadminClient, resolv: dnsResolver, srcDomain: domainConfig.Source.Name, srcNameserver: domainConfig.Source.Nameserver, dstDomain: domainConfig.Destination.Name, dstNameserver: domainConfig.Destination.Nameserver, entryName: domainConfig.Entry.Name, entryDomain: domainConfig.Entry.Domain, entryTTL: domainConfig.Entry.TTL, resyncTime: resyncTime, log: log, } } func (s *Service) update() { srcIPs, err := s.resolv.ResolveA(s.srcDomain, s.srcNameserver) if err != nil { s.log.Warn().Err(err).Msg("unable to get source IP address") return } srcIP := srcIPs[0] s.log.Info().IPAddr("ip", srcIP).Msg("got source IP address") dstIPs, err := s.resolv.ResolveA(s.dstDomain, s.dstNameserver) if err != nil { s.log.Warn().Err(err).Msg("unable to get destination IP address") return } dstIP := dstIPs[0] s.log.Info().IPAddr("ip", dstIP).Msg("got destination IP address") if srcIP.Equal(dstIP) { s.log.Info().Msg("addresses match, no update needed") return } s.log.Info().Msg("addresses mismatch, updating") params := &directadmin.DNSControlParams{ Domain: s.entryDomain, Action: directadmin.DNSControlActionEdit, Type: directadmin.DNSControlRecordTypeA, Name: s.entryName, Value: srcIP.String(), TTL: &s.entryTTL, ARECS0: fmt.Sprintf( "name=%s&value=%s", s.entryName, dstIP.String(), ), } log := s.log.With().Object("params", params).Logger() resp, err := s.da.DNSControl(params) if err != nil { log.Error().Err(err).Msg("unable to update domain params") return } log = log.With().Object("response", resp).Logger() if resp.Error { log.Error().Msg("unable to update domain params") return } log.Info().Msg("successfully updated domain params") } func (s *Service) Run(ctx context.Context) error { ticker := time.NewTicker(s.resyncTime) defer ticker.Stop() for { s.update() select { case <-ctx.Done(): return nil case <-ticker.C: continue } } }