diff options
Diffstat (limited to 'main.go')
| -rw-r--r-- | main.go | 118 |
1 files changed, 118 insertions, 0 deletions
@@ -0,0 +1,118 @@ +// dynamic domain no-name system service +// +// a simple dynamic dns record updating utility which fetches your +// ip address from a source, and lets a provider know of the fresh +// address. +package main + +import ( + "flag" + "fmt" + "log/slog" + "os" + + "git.rnrd.eu/ddnnss/provider" + "git.rnrd.eu/ddnnss/source" +) + +const version = "1.0.0" + +func main() { + configPath := flag.String("config", "/etc/ddnnss.json", "config file") + showVersion := flag.Bool("version", false, "print the version and exit") + flag.Parse() + + if *showVersion { + fmt.Println("ddnnss", version) + return + } + + slog.Info("ddnnss!", slog.String("version", version)) + + cfg, err := LoadConfig(*configPath) + if err != nil { + slog.Error("could not load config", slog.String("error", err.Error())) + os.Exit(1) + } + + providers := map[string]provider.Provider{} + sources := map[string]source.Source{} + + slog.Info("starting new cycle", slog.Int("records", len(cfg.Records))) + + failed := false + for _, r := range cfg.Records { + fqdn := r.Name + "." + r.Zone + log := slog.With("record", fqdn, "type", r.Type) + + log.Info( + "ensuring record", + slog.String("provider", r.Provider), + slog.String("source", r.Source), + ) + + p, ok := providers[r.Provider] + if !ok { + p, err = provider.New(log, cfg.Providers[r.Provider]) + if err != nil { + log.Error("provider setup failed", "provider", r.Provider, "error", err) + failed = true + continue + } + providers[r.Provider] = p + } + + s, ok := sources[r.Source] + if !ok { + s, err = source.New(log, cfg.Sources[r.Source]) + if err != nil { + log.Error("source setup failed", "source", r.Source, "error", err) + failed = true + continue + } + sources[r.Source] = s + } + + family := source.IPv4 + if r.Type == provider.TypeAAAA { + family = source.IPv6 + } + if !s.Supports(family) { + log.Error("source cannot provide the needed address family", + "source", r.Source, "family", family) + failed = true + continue + } + + addr, err := s.Lookup(family) + if err != nil { + log.Error("address lookup failed", "source", r.Source, "error", err) + failed = true + continue + } + + prev, changed, err := p.Ensure(r.Zone, r.Name, r.Type, addr) + switch { + case err != nil: + log.Error("update failed", "error", err) + failed = true + case changed && prev == "": + log.Info("record created", "addr", addr) + case changed: + log.Info("record updated", "from", prev, "to", addr) + default: + log.Info("record unchanged", "addr", addr) + } + } + + slog.Info( + "cycle finished", + slog.Int("records", len(cfg.Records)), + slog.Bool("failed", failed), + ) + + if failed { + slog.Error("not all records were ensured successfully") + os.Exit(1) + } +} |
