// Package that will query for IP package checker import ( "errors" "io" "log/slog" "net" "net/http" "strings" "github.com/maximotejeda/ddns/config" ) type client struct { urls []string method string headers map[string][]string reqs []*http.Request log *slog.Logger } type Response struct { IP *net.IP `json:"ip,omitempty" yaml:"ip,omitempty"` IPSTR string `json:"ip_str,omitempty" yaml:"ip_str,omitempty"` Version string `json:"version" yaml:"version,omitempty"` Type string `json:"type,omitempty" yaml:"type,omitempty"` Identifyer string `json:"identifyer" yaml:"identifyer"` } func NewClient(log *slog.Logger, provider string) *client { c := &client{} c.urls = strings.Split(config.GetServiceVerifyURL("IP_VERIFY_PROVIDER_URL"), ",") c.method = http.MethodGet for _, url := range c.urls { req, _ := http.NewRequest(c.method, url, nil) c.reqs = append(c.reqs, req) } log = log.With("location", "Checker") c.log = log return c } // Do // Make a request to retrieve the ip of the machine func (c *client) Do() (res *Response, err error) { r := &Response{} client := http.DefaultClient if len(c.reqs) <= 0 { c.log.Error("no request on struct") return nil, errors.New("no request on client struct") } resp, err := client.Do(c.reqs[0]) r.Identifyer = c.urls[0] if err != nil { c.log.Error("doing request for ip", "err", err, "identidyer", c.reqs[0]) c.log.Info("retrying on other provider") resp, err = client.Do(c.reqs[1]) r.Identifyer = c.urls[1] if err != nil { c.log.Error("doing request for ip", "err", err, "identidyer", c.reqs[1]) return nil, err } } defer resp.Body.Close() ipSTR, err := io.ReadAll(resp.Body) if err != nil { c.log.Error("reading body", "error", err.Error()) } ipi := net.ParseIP(string(ipSTR)) r.IP = &ipi //check ip is not nil if r.IP == nil { return nil, errors.New("ip not found") } // check if ip is private if r.IP.IsPrivate() { return nil, errors.New("ip is a private ip") } // check if is loop back ip if r.IP.IsLoopback() { return nil, errors.New("ip is a loopback ip") } if r.IP.To4() != nil { r.Version = "V4" r.Type = "A" }else { r.Version = "V6" r.Type = "AAAA" } return r, err }