diff --git a/api/api.go b/api/api.go index d4e8fe1..2df7df3 100644 --- a/api/api.go +++ b/api/api.go @@ -1,6 +1,7 @@ package api import ( + "bytes" "encoding/json" "errors" "fmt" @@ -74,9 +75,83 @@ func (api API) performRequest(method, url string, body io.Reader) (response []by return ioutil.ReadAll(resp.Body) } -// Returns a slice of DNS records associated with a given hostname. -func (api API) GetRecords(hostname string) (records []DNSRecord, err error) { - resp, err := api.performRequest("GET", fmt.Sprintf("%s%s%s", api.baseUrl, "api/dns/list/", hostname), nil) +func (api API) CreateDNSRecord(domain string, record DNSRecord) error { + b, err := json.Marshal(record) + if err != nil { + return err + } + + resp, err := api.performRequest( + "POST", + fmt.Sprintf("%s%s%s", api.baseUrl, "api/dns/create/", domain), + bytes.NewBuffer(b), + ) + if err != nil { + return err + } + + var result struct { + Result resultResponse + } + + err = json.Unmarshal(resp, &result) + if err != nil { + return err + } + if result.Result.Code != 100 { + return errors.New(result.Result.Message) + } + + return nil +} + +func (api API) DeleteDNSRecord(domain, recordId string) error { + var body struct { + RecordId string `json:"record_id"` + } + body.RecordId = recordId + + b, err := json.Marshal(body) + if err != nil { + return err + } + + fmt.Println("Body:", string(b)) + + resp, err := api.performRequest( + "POST", + fmt.Sprintf("%s%s%s", api.baseUrl, "api/dns/delete/", domain), + bytes.NewBuffer(b), + ) + if err != nil { + return err + } + + fmt.Println("Response:", string(resp)) + + var result struct { + Result resultResponse + } + + err = json.Unmarshal(resp, &result) + if err != nil { + return err + } + if result.Result.Code != 100 { + return errors.New(result.Result.Message) + } + + return nil +} + +// Returns a slice of DNS records associated with a given domain. +func (api API) GetRecords(domain string) (records []DNSRecord, err error) { + resp, err := api.performRequest( + "GET", + fmt.Sprintf("%s%s%s", api.baseUrl, "api/dns/list/", domain), + nil, + ) + if err != nil { return nil, err } @@ -90,8 +165,6 @@ func (api API) GetRecords(hostname string) (records []DNSRecord, err error) { if err != nil { return nil, err } - - // Make sure the API call was successful if result.Result.Code != 100 { return nil, errors.New(result.Result.Message) } diff --git a/dyndns/daemon.go b/dyndns/daemon.go index 7f3552a..4fb9a84 100644 --- a/dyndns/daemon.go +++ b/dyndns/daemon.go @@ -9,23 +9,16 @@ import ( var wg sync.WaitGroup -func updateDomain(a api.API, currentIP, domain string) error { - records, err := a.GetRecords(domain) +func updateDNSRecord(a api.API, domain, recordId string, newRecord api.DNSRecord) error { + fmt.Println("Deleting record...") + err := a.DeleteDNSRecord(domain, newRecord.RecordId) if err != nil { return err } - if len(records) == 0 { - return nil - } - - for _, record := range records { - if record.Content != currentIP { - // TODO: Update - } - } - - return nil + // Does a /create/ overwrite? or do we have to delete first? + fmt.Println("Creating record") + return a.CreateDNSRecord(domain, newRecord) } func runConfig(c api.Config, daemon bool) { @@ -35,7 +28,7 @@ func runConfig(c api.Config, daemon bool) { for { ip, err := GetExternalIP() if err != nil { - fmt.Print("Failed to retreive IP: ") + fmt.Print("Fail to retreive IP: ") if daemon { fmt.Println("Will retry...") continue @@ -45,8 +38,31 @@ func runConfig(c api.Config, daemon bool) { } } - for _, domain := range c.Domains { - updateDomain(a, ip, domain) + // GetRecords retrieves a list of DNSRecords, + // 1 per hostname with the associated domain. + // If the content is not the current IP, then + // update it. + records, err := a.GetRecords(c.Domain) + if err != nil { + fmt.Print("Failed to retreive records for:%s\n", c.Domain) + if daemon { + fmt.Println("Will retry...") + continue + } else { + fmt.Println("Giving up.") + break + } + } + + for _, r := range records { + if r.Content != ip { + fmt.Printf("Updating record %s for %s\n", r.RecordId, c.Domain) + r.Content = ip + err = updateDNSRecord(a, c.Domain, r.RecordId, r) + if err != nil { + fmt.Println("Failed to update record.", err) + } + } } if !daemon { diff --git a/main.go b/main.go index f443ca9..9d66793 100644 --- a/main.go +++ b/main.go @@ -8,9 +8,20 @@ import ( "os" ) +func filterConfigs(configs []api.Config, dev bool) []api.Config { + for i := 0; i < len(configs); i++ { + if configs[i].Dev != dev { + configs = append(configs[:i], configs[i+1:]...) + } + } + + return configs +} + func main() { configPath := flag.String("config", "./config.json", "Specify the configuration file") - daemon := flag.Bool("daemon", false, "operate in daemon mode") + daemon := flag.Bool("daemon", false, "Operate in daemon mode.") + dev := flag.Bool("dev", false, "Use development configurations instead.") flag.Parse() configs, err := api.LoadConfigs(*configPath) @@ -20,6 +31,8 @@ func main() { return } + configs = filterConfigs(configs, *dev) + fmt.Printf("Successfully loaded %d configs\n", len(configs)) dyndns.Run(configs, *daemon) }