diff --git a/pkg/provider/main.go b/pkg/provider/main.go index fed8fce..4ad19a2 100644 --- a/pkg/provider/main.go +++ b/pkg/provider/main.go @@ -15,6 +15,7 @@ type Provider interface { UpdateSubdomains(ip string) error updateSubdomain(subdomain, ip string) error retrieveSubdomainIP(addr string) (string, error) + checkResponse(body []byte, tokenBased bool, ip string) error } type provider struct { @@ -96,7 +97,7 @@ func (p *provider) updateSubdomain(subdomain, ip string) error { req, err := http.NewRequest("GET", newURL, nil) if err != nil { - return utils.ErrCreateNewRequest + return fmt.Errorf("%v: %v", utils.ErrCreateNewRequest, err) } if !tokenBased { req.SetBasicAuth(p.config.Username, p.config.Password) @@ -134,14 +135,14 @@ func (p *provider) retrieveSubdomainIP(addr string) (string, error) { } if len(ips) != 1 { - return "", utils.ErrIpLenght + return "", fmt.Errorf("%v: %v", utils.ErrIpLenght, ips) } ip := ips[0].String() if strings.Contains(ip, ":") { ip, _, err = net.SplitHostPort(ip) if err != nil { - return "", utils.ErrSplitAddr + return "", fmt.Errorf("%v: %v", utils.ErrSplitAddr, ip) } } diff --git a/pkg/utils/types.go b/pkg/utils/types.go index 1887045..3f8d07d 100644 --- a/pkg/utils/types.go +++ b/pkg/utils/types.go @@ -13,7 +13,7 @@ var ( // ErrGetServerIP is thrown when HTTP can't contact the web-ip service ErrGetServerIP = errors.New("HTTP error") // ErrParseHTTPBody is thrown when the HTTP service can't parse the body response - ErrParseHTTPBody = errors.New("can't parse response body") + ErrParseHTTPBody = errors.New("can't read response body") // ErrSplitAddr is thrown when the remote address can't be splitted ErrSplitAddr = errors.New("can't split subdomain remote IP address") // ErrCreateNewRequest is thrown when http request creation failed diff --git a/pkg/watcher/watcher.go b/pkg/watcher/watcher.go index 9879507..89e4f6d 100644 --- a/pkg/watcher/watcher.go +++ b/pkg/watcher/watcher.go @@ -1,8 +1,12 @@ package watcher import ( + "encoding/json" + "fmt" "io/ioutil" + "net" "net/http" + "strings" "time" "github.com/datahearth/ddnsclient/pkg/provider" @@ -102,18 +106,66 @@ func (w *watcher) runDDNSCheck() error { } func (w *watcher) retrieveServerIP() (string, error) { - resp, err := http.Get(w.webIP) + rsp, err := http.Get(w.webIP) if err != nil { - return "", utils.ErrGetServerIP + return "", fmt.Errorf("%v: %v", utils.ErrGetServerIP, err) } - if resp.StatusCode != 200 { - return "", utils.ErrWrongStatusCode + if rsp.StatusCode != 200 { + return "", fmt.Errorf("%v: %v", utils.ErrWrongStatusCode, rsp.Status) } - d, err := ioutil.ReadAll(resp.Body) + b, err := ioutil.ReadAll(rsp.Body) if err != nil { - return "", utils.ErrParseHTTPBody + return "", fmt.Errorf("%v: %v", utils.ErrParseHTTPBody, err) } - return string(d), nil + var ip string + if rsp.Header.Get("content-type") == "application/json" { + body := make(map[string]interface{}) + if err := json.Unmarshal(b, &body); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON body: %v", err) + } + + if v, ok := body["ip"]; ok { + if v, ok := v.(string); ok { + ip = v + } else { + return "", fmt.Errorf("\"ip\" field found in JSON response but is not a string value") + } + } else { + for _, v := range body { + if v, ok := v.(string); ok { + if parsedIP := net.ParseIP(v); parsedIP != nil { + ip = parsedIP.String() + } + } + } + + if ip == "" { + return "", fmt.Errorf("no field found with a valid IPv4 address in JSON response") + } + } + } else { + body := string(b) + if strings.Count(body, "\n") > 0 { + for _, l := range strings.Split(body, "\n") { + if parsedIP := net.ParseIP(l); parsedIP != nil { + ip = parsedIP.String() + break + } + } + + if ip == "" { + return "", fmt.Errorf("no field found with a valid IPv4 address in body response") + } + } else { + if body == "" { + return "", fmt.Errorf("body is empty") + } + ip = body + } + + } + + return ip, nil }