From 5d4f3b9af484c429dfee5de7ab6d69adacb8dfed Mon Sep 17 00:00:00 2001
From: CyberAustin <88937794+CyberAustin@users.noreply.github.com>
Date: Fri, 2 Feb 2024 14:35:39 +0000
Subject: [PATCH 01/23] Have GoIP.de mostly working, just need to finish
implementing error messages.
---
README.md | 2 +
docs/goip.md | 35 ++++
internal/provider/constants/providers.go | 2 +
internal/provider/provider.go | 3 +
internal/provider/providers/goip/provider.go | 169 +++++++++++++++++++
5 files changed, 211 insertions(+)
create mode 100644 docs/goip.md
create mode 100644 internal/provider/providers/goip/provider.go
diff --git a/README.md b/README.md
index 5c8fa1c03..aadedd9cf 100644
--- a/README.md
+++ b/README.md
@@ -52,6 +52,7 @@ Light container updating DNS A and/or AAAA records periodically for multiple DNS
- Gandi
- GCP
- GoDaddy
+ - GoIP.de
- He.net
- Hetzner
- Infomaniak
@@ -189,6 +190,7 @@ Check the documentation for your DNS provider:
- [Gandi](https://github.com/qdm12/ddns-updater/blob/master/docs/gandi.md)
- [GCP](https://github.com/qdm12/ddns-updater/blob/master/docs/gcp.md)
- [GoDaddy](https://github.com/qdm12/ddns-updater/blob/master/docs/godaddy.md)
+- [GoIP.de](https://github.com/qdm12/ddns-updater/blob/master/docs/goip.md)
- [He.net](https://github.com/qdm12/ddns-updater/blob/master/docs/he.net.md)
- [Infomaniak](https://github.com/qdm12/ddns-updater/blob/master/docs/infomaniak.md)
- [INWX](https://github.com/qdm12/ddns-updater/blob/master/docs/inwx.md)
diff --git a/docs/goip.md b/docs/goip.md
new file mode 100644
index 000000000..adc68fd6a
--- /dev/null
+++ b/docs/goip.md
@@ -0,0 +1,35 @@
+# GoIP.de
+
+## Configuration
+
+### Example
+
+```json
+{
+ "settings": [
+ {
+ "provider": "goip.de",
+ "domain": "subdomain",
+ "username": "username",
+ "password": "password",
+ "provider_ip": true,
+ "ip_version": "ipv4",
+ "ipv6_suffix": ""
+ }
+ ]
+}
+```
+
+### Compulsory parameters
+
+- `"domain"`
+- `"username"` is your goip.de username listed un "Routers"
+- `"password"` is your router username password
+
+### Optional parameters
+
+- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
+- `"ipv6_suffix"` is the IPv6 interface identifiersuffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
+- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
+
+## Domain setup
diff --git a/internal/provider/constants/providers.go b/internal/provider/constants/providers.go
index f7ceb913f..646f08f4c 100644
--- a/internal/provider/constants/providers.go
+++ b/internal/provider/constants/providers.go
@@ -25,6 +25,7 @@ const (
Gandi models.Provider = "gandi"
GCP models.Provider = "gcp"
GoDaddy models.Provider = "godaddy"
+ GoIP models.Provider = "goip"
HE models.Provider = "he"
Hetzner models.Provider = "hetzner"
Infomaniak models.Provider = "infomaniak"
@@ -71,6 +72,7 @@ func ProviderChoices() []models.Provider {
Gandi,
GCP,
GoDaddy,
+ GoIP,
HE,
Hetzner,
Infomaniak,
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index cd01912de..6a03c1770 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -31,6 +31,7 @@ import (
"github.com/qdm12/ddns-updater/internal/provider/providers/gandi"
"github.com/qdm12/ddns-updater/internal/provider/providers/gcp"
"github.com/qdm12/ddns-updater/internal/provider/providers/godaddy"
+ "github.com/qdm12/ddns-updater/internal/provider/providers/goip"
"github.com/qdm12/ddns-updater/internal/provider/providers/he"
"github.com/qdm12/ddns-updater/internal/provider/providers/hetzner"
"github.com/qdm12/ddns-updater/internal/provider/providers/infomaniak"
@@ -116,6 +117,8 @@ func New(providerName models.Provider, data json.RawMessage, domain, host string
return gcp.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.GoDaddy:
return godaddy.New(data, domain, host, ipVersion, ipv6Suffix)
+ case constants.GoIP:
+ return goip.New(data, domain, ipVersion, ipv6Suffix)
case constants.HE:
return he.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Hetzner:
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
new file mode 100644
index 000000000..b007500f8
--- /dev/null
+++ b/internal/provider/providers/goip/provider.go
@@ -0,0 +1,169 @@
+package goip
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/netip"
+ "net/url"
+ "strings"
+
+ "github.com/qdm12/ddns-updater/internal/models"
+ "github.com/qdm12/ddns-updater/internal/provider/constants"
+ "github.com/qdm12/ddns-updater/internal/provider/errors"
+ "github.com/qdm12/ddns-updater/internal/provider/headers"
+ "github.com/qdm12/ddns-updater/internal/provider/utils"
+ "github.com/qdm12/ddns-updater/pkg/publicip/ipversion"
+)
+
+type Provider struct {
+ domain string
+ ipVersion ipversion.IPVersion
+ ipv6Suffix netip.Prefix
+ username string
+ password string
+ useProviderIP bool
+}
+
+func New(data json.RawMessage, domain string,
+ ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
+ p *Provider, err error) {
+ extraSettings := struct {
+ Username string `json:"username"`
+ Password string `json:"password"`
+ UseProviderIP bool `json:"providor_ip"`
+ }{}
+ err = json.Unmarshal(data, &extraSettings)
+ if err != nil {
+ return nil, err
+ }
+ p = &Provider{
+ domain: domain,
+ ipVersion: ipVersion,
+ ipv6Suffix: ipv6Suffix,
+ username: extraSettings.Username,
+ password: extraSettings.Password,
+ useProviderIP: extraSettings.UseProviderIP,
+ }
+ err = p.isValid()
+ if err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+func (p *Provider) isValid() error {
+ switch {
+ case p.username == "":
+ return fmt.Errorf("%w", errors.ErrUsernameNotSet)
+ case p.password == "":
+ return fmt.Errorf("%w", errors.ErrPasswordNotSet)
+ }
+ return nil
+}
+
+func (p *Provider) String() string {
+ return utils.ToString(p.domain,"@", constants.GoIP, p.ipVersion)
+}
+
+func (p *Provider) Domain() string {
+ return p.domain
+}
+
+func (p *Provider) Host() string {
+ return "@"
+}
+
+func (p *Provider) IPVersion() ipversion.IPVersion {
+ return p.ipVersion
+}
+
+func (p *Provider) IPv6Suffix() netip.Prefix {
+ return p.ipv6Suffix
+}
+
+func (p *Provider) Proxied() bool {
+ return false
+}
+
+func (p *Provider) BuildDomainName() string {
+ return p.domain
+}
+
+func (p *Provider) HTML() models.HTMLRow {
+ return models.HTMLRow{
+ Domain: fmt.Sprintf("%s", p.BuildDomainName(), p.BuildDomainName()),
+ Host: p.Host(),
+ Provider: "GoIP.de",
+ IPVersion: p.ipVersion.String(),
+ }
+}
+//https://www.goip.de/setip?username=%5BUser%5D&password=%5BPass%5D&subdomain=%5Bsubdomain.goip.de%5D
+func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Addr) (newIP netip.Addr, err error) {
+ u := url.URL{
+ Scheme: "https",
+ User: url.UserPassword(p.username, p.password),
+ Host: "www.goip.de",
+ Path: "/setip",
+ }
+ values := url.Values{}
+ values.Set("subdomain", p.domain)
+ values.Set("username", p.username)
+ values.Set("password", p.password)
+ values.Set("shortResponse", "true")
+ useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
+ if !useProviderIP {
+ values.Set("ip", ip.String())
+ }
+ u.RawQuery = values.Encode()
+
+ request, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
+ fmt.Println(request)
+ if err != nil {
+ return netip.Addr{}, fmt.Errorf("creating http request: %w", err)
+ }
+ headers.SetUserAgent(request)
+
+ response, err := client.Do(request)
+ if err != nil {
+ return netip.Addr{}, fmt.Errorf("doing http request: %w", err)
+ }
+ defer response.Body.Close()
+
+ switch response.StatusCode {
+ case http.StatusOK:
+ case http.StatusNoContent:
+ return ip, nil
+ case http.StatusUnauthorized:
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrAuth)
+ case http.StatusConflict:
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrZoneNotFound)
+ case http.StatusGone:
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrAccountInactive)
+ case http.StatusLengthRequired:
+ return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrIPSentMalformed, ip)
+ case http.StatusPreconditionFailed:
+ return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrPrivateIPSent, ip)
+ case http.StatusServiceUnavailable:
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrDNSServerSide)
+ default:
+ return netip.Addr{}, fmt.Errorf("%w: %d: %s",
+ errors.ErrHTTPStatusNotValid, response.StatusCode, utils.BodyToSingleLine(response.Body))
+ }
+
+ b, err := io.ReadAll(response.Body)
+ if err != nil {
+ return netip.Addr{}, fmt.Errorf("reading response body: %w", err)
+ }
+ s := string(b)
+ fmt.Println("Start:" + s + ":End")
+ switch {
+ case strings.HasPrefix(s, p.domain + " (" + ip.String() + ")"):
+ fmt.Println("All good")
+ return ip, nil
+ default:
+ return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, s)
+ }
+}
From 9ed3041e434f5111abe81cf2619cd9ae4479d511 Mon Sep 17 00:00:00 2001
From: CyberAustin
Date: Fri, 2 Feb 2024 19:06:55 +0100
Subject: [PATCH 02/23] Ready to merge, or at least so I think
---
internal/provider/providers/goip/provider.go | 21 ++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index b007500f8..aa739735f 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -65,7 +65,7 @@ func (p *Provider) isValid() error {
}
func (p *Provider) String() string {
- return utils.ToString(p.domain,"@", constants.GoIP, p.ipVersion)
+ return utils.ToString(p.domain, "@", constants.GoIP, p.ipVersion)
}
func (p *Provider) Domain() string {
@@ -100,7 +100,7 @@ func (p *Provider) HTML() models.HTMLRow {
IPVersion: p.ipVersion.String(),
}
}
-//https://www.goip.de/setip?username=%5BUser%5D&password=%5BPass%5D&subdomain=%5Bsubdomain.goip.de%5D
+
func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Addr) (newIP netip.Addr, err error) {
u := url.URL{
Scheme: "https",
@@ -110,9 +110,9 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("subdomain", p.domain)
- values.Set("username", p.username)
- values.Set("password", p.password)
- values.Set("shortResponse", "true")
+ values.Set("username", p.username)
+ values.Set("password", p.password)
+ values.Set("shortResponse", "true")
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
values.Set("ip", ip.String())
@@ -120,7 +120,6 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
u.RawQuery = values.Encode()
request, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
- fmt.Println(request)
if err != nil {
return netip.Addr{}, fmt.Errorf("creating http request: %w", err)
}
@@ -158,11 +157,13 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
return netip.Addr{}, fmt.Errorf("reading response body: %w", err)
}
s := string(b)
- fmt.Println("Start:" + s + ":End")
switch {
- case strings.HasPrefix(s, p.domain + " (" + ip.String() + ")"):
- fmt.Println("All good")
- return ip, nil
+ case strings.HasPrefix(s, p.domain+" ("+ip.String()+")"):
+ return ip, nil
+ case strings.HasPrefix(s, "Zugriff verweigert"):
+ return netip.Addr{}, fmt.Errorf("Username, Password or Subdomain incorrect")
+ case strings.HasPrefix(s, "Die Datenübertragung war fehlerhaft"):
+ return netip.Addr{}, fmt.Errorf(("IP address incorrectly formatted"))
default:
return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, s)
}
From 431c31ee4cd4462db34e4fc4f911a523f4135d61 Mon Sep 17 00:00:00 2001
From: CyberAustin
Date: Fri, 2 Feb 2024 21:18:45 +0100
Subject: [PATCH 03/23] Fixed or adjusted most comments. Ready for another
review.
---
docs/goip.md | 16 ++++--------
internal/provider/constants/providers.go | 4 +--
internal/provider/provider.go | 6 ++---
internal/provider/providers/goip/provider.go | 26 +++++++++-----------
4 files changed, 21 insertions(+), 31 deletions(-)
diff --git a/docs/goip.md b/docs/goip.md
index adc68fd6a..aa66dc7d1 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -9,12 +9,10 @@
"settings": [
{
"provider": "goip.de",
- "domain": "subdomain",
+ "subdomain": "subdomain",
"username": "username",
"password": "password",
"provider_ip": true,
- "ip_version": "ipv4",
- "ipv6_suffix": ""
}
]
}
@@ -22,14 +20,10 @@
### Compulsory parameters
-- `"domain"`
-- `"username"` is your goip.de username listed un "Routers"
-- `"password"` is your router username password
+- `"subdomain"`
+- `"username"` is your goip.de username listed under "Routers"
+- `"password"` is your router account password
### Optional parameters
-- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
-- `"ipv6_suffix"` is the IPv6 interface identifiersuffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
-- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
-
-## Domain setup
+- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
\ No newline at end of file
diff --git a/internal/provider/constants/providers.go b/internal/provider/constants/providers.go
index 646f08f4c..38e0d0db1 100644
--- a/internal/provider/constants/providers.go
+++ b/internal/provider/constants/providers.go
@@ -25,7 +25,7 @@ const (
Gandi models.Provider = "gandi"
GCP models.Provider = "gcp"
GoDaddy models.Provider = "godaddy"
- GoIP models.Provider = "goip"
+ GoIP models.Provider = "goip"
HE models.Provider = "he"
Hetzner models.Provider = "hetzner"
Infomaniak models.Provider = "infomaniak"
@@ -72,7 +72,7 @@ func ProviderChoices() []models.Provider {
Gandi,
GCP,
GoDaddy,
- GoIP,
+ GoIP,
HE,
Hetzner,
Infomaniak,
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 6a03c1770..d0bc06971 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -31,7 +31,7 @@ import (
"github.com/qdm12/ddns-updater/internal/provider/providers/gandi"
"github.com/qdm12/ddns-updater/internal/provider/providers/gcp"
"github.com/qdm12/ddns-updater/internal/provider/providers/godaddy"
- "github.com/qdm12/ddns-updater/internal/provider/providers/goip"
+ "github.com/qdm12/ddns-updater/internal/provider/providers/goip"
"github.com/qdm12/ddns-updater/internal/provider/providers/he"
"github.com/qdm12/ddns-updater/internal/provider/providers/hetzner"
"github.com/qdm12/ddns-updater/internal/provider/providers/infomaniak"
@@ -117,8 +117,8 @@ func New(providerName models.Provider, data json.RawMessage, domain, host string
return gcp.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.GoDaddy:
return godaddy.New(data, domain, host, ipVersion, ipv6Suffix)
- case constants.GoIP:
- return goip.New(data, domain, ipVersion, ipv6Suffix)
+ case constants.GoIP:
+ return goip.New(data, domain, ipVersion, ipv6Suffix)
case constants.HE:
return he.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Hetzner:
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index aa739735f..f96789900 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -19,7 +19,7 @@ import (
)
type Provider struct {
- domain string
+ subdomain string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
@@ -27,7 +27,7 @@ type Provider struct {
useProviderIP bool
}
-func New(data json.RawMessage, domain string,
+func New(data json.RawMessage, subdomain string,
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
@@ -40,7 +40,7 @@ func New(data json.RawMessage, domain string,
return nil, err
}
p = &Provider{
- domain: domain,
+ subdomain: subdomain,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
@@ -64,14 +64,16 @@ func (p *Provider) isValid() error {
return nil
}
+// "@" necessary to prevent ToString from appending a "." to the FQDN
func (p *Provider) String() string {
- return utils.ToString(p.domain, "@", constants.GoIP, p.ipVersion)
+ return utils.ToString(p.subdomain, "@", constants.GoIP, p.ipVersion)
}
func (p *Provider) Domain() string {
- return p.domain
+ return p.subdomain
}
+// "@" hard coded for compatibility with other provider implementations
func (p *Provider) Host() string {
return "@"
}
@@ -89,7 +91,7 @@ func (p *Provider) Proxied() bool {
}
func (p *Provider) BuildDomainName() string {
- return p.domain
+ return p.subdomain
}
func (p *Provider) HTML() models.HTMLRow {
@@ -109,7 +111,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
Path: "/setip",
}
values := url.Values{}
- values.Set("subdomain", p.domain)
+ values.Set("subdomain", p.subdomain)
values.Set("username", p.username)
values.Set("password", p.password)
values.Set("shortResponse", "true")
@@ -133,8 +135,6 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
switch response.StatusCode {
case http.StatusOK:
- case http.StatusNoContent:
- return ip, nil
case http.StatusUnauthorized:
return netip.Addr{}, fmt.Errorf("%w", errors.ErrAuth)
case http.StatusConflict:
@@ -143,8 +143,6 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
return netip.Addr{}, fmt.Errorf("%w", errors.ErrAccountInactive)
case http.StatusLengthRequired:
return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrIPSentMalformed, ip)
- case http.StatusPreconditionFailed:
- return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrPrivateIPSent, ip)
case http.StatusServiceUnavailable:
return netip.Addr{}, fmt.Errorf("%w", errors.ErrDNSServerSide)
default:
@@ -158,12 +156,10 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
s := string(b)
switch {
- case strings.HasPrefix(s, p.domain+" ("+ip.String()+")"):
+ case strings.HasPrefix(s, p.subdomain+" ("+ip.String()+")"):
return ip, nil
- case strings.HasPrefix(s, "Zugriff verweigert"):
+ case strings.HasPrefix(strings.ToLower(s), "zugriff verweigert"):
return netip.Addr{}, fmt.Errorf("Username, Password or Subdomain incorrect")
- case strings.HasPrefix(s, "Die Datenübertragung war fehlerhaft"):
- return netip.Addr{}, fmt.Errorf(("IP address incorrectly formatted"))
default:
return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, s)
}
From 99e660292effba9543a34c986e58bdd88f0a204b Mon Sep 17 00:00:00 2001
From: CyberAustin
Date: Fri, 2 Feb 2024 21:37:47 +0100
Subject: [PATCH 04/23] Fixed some linting errors and changed subdomain to FQDN
to make more sense
---
docs/goip.md | 4 ++--
internal/provider/errors/validation.go | 1 +
internal/provider/providers/goip/provider.go | 22 ++++++++++----------
3 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/docs/goip.md b/docs/goip.md
index aa66dc7d1..6c181d0c2 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -9,7 +9,7 @@
"settings": [
{
"provider": "goip.de",
- "subdomain": "subdomain",
+ "fqdn": "mysubdomain.goip.de",
"username": "username",
"password": "password",
"provider_ip": true,
@@ -20,7 +20,7 @@
### Compulsory parameters
-- `"subdomain"`
+- `"subdomain"` is the full FQDN of your ddns address. sample.goip.de or something.goip.it
- `"username"` is your goip.de username listed under "Routers"
- `"password"` is your router account password
diff --git a/internal/provider/errors/validation.go b/internal/provider/errors/validation.go
index c98bc2b5f..6721e9d6a 100644
--- a/internal/provider/errors/validation.go
+++ b/internal/provider/errors/validation.go
@@ -23,6 +23,7 @@ var (
ErrNameNotSet = errors.New("name is not set")
ErrPasswordNotSet = errors.New("password is not set")
ErrPasswordNotValid = errors.New("password is not valid")
+ ErrParametersNotValid = errors.New("Username, Password or FQDN incorrect")
ErrSecretNotSet = errors.New("secret is not set")
ErrSuccessRegexNotSet = errors.New("success regex is not set")
ErrTokenNotSet = errors.New("token is not set")
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index f96789900..4393e36ee 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -19,7 +19,7 @@ import (
)
type Provider struct {
- subdomain string
+ fqdn string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
@@ -27,7 +27,7 @@ type Provider struct {
useProviderIP bool
}
-func New(data json.RawMessage, subdomain string,
+func New(data json.RawMessage, fqdn string,
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
@@ -40,7 +40,7 @@ func New(data json.RawMessage, subdomain string,
return nil, err
}
p = &Provider{
- subdomain: subdomain,
+ fqdn: fqdn,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
@@ -64,16 +64,16 @@ func (p *Provider) isValid() error {
return nil
}
-// "@" necessary to prevent ToString from appending a "." to the FQDN
+// "@" necessary to prevent ToString from appending a "." to the FQDN.
func (p *Provider) String() string {
- return utils.ToString(p.subdomain, "@", constants.GoIP, p.ipVersion)
+ return utils.ToString(p.fqdn, "@", constants.GoIP, p.ipVersion)
}
func (p *Provider) Domain() string {
- return p.subdomain
+ return p.fqdn
}
-// "@" hard coded for compatibility with other provider implementations
+// "@" hard coded for compatibility with other provider implementations.
func (p *Provider) Host() string {
return "@"
}
@@ -91,7 +91,7 @@ func (p *Provider) Proxied() bool {
}
func (p *Provider) BuildDomainName() string {
- return p.subdomain
+ return p.fqdn
}
func (p *Provider) HTML() models.HTMLRow {
@@ -111,7 +111,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
Path: "/setip",
}
values := url.Values{}
- values.Set("subdomain", p.subdomain)
+ values.Set("fqdn", p.fqdn)
values.Set("username", p.username)
values.Set("password", p.password)
values.Set("shortResponse", "true")
@@ -156,10 +156,10 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
s := string(b)
switch {
- case strings.HasPrefix(s, p.subdomain+" ("+ip.String()+")"):
+ case strings.HasPrefix(s, p.fqdn+" ("+ip.String()+")"):
return ip, nil
case strings.HasPrefix(strings.ToLower(s), "zugriff verweigert"):
- return netip.Addr{}, fmt.Errorf("Username, Password or Subdomain incorrect")
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrParametersNotValid)
default:
return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, s)
}
From 8f3a58eaa77697067be756a09915bc1c533b475f Mon Sep 17 00:00:00 2001
From: CyberAustin <88937794+CyberAustin@users.noreply.github.com>
Date: Fri, 2 Feb 2024 14:35:39 +0000
Subject: [PATCH 05/23] Have GoIP.de mostly working, just need to finish
implementing error messages.
---
README.md | 2 +
docs/goip.md | 35 ++++
internal/provider/constants/providers.go | 2 +
internal/provider/provider.go | 3 +
internal/provider/providers/goip/provider.go | 169 +++++++++++++++++++
5 files changed, 211 insertions(+)
create mode 100644 docs/goip.md
create mode 100644 internal/provider/providers/goip/provider.go
diff --git a/README.md b/README.md
index ea77a6229..46b3b562f 100644
--- a/README.md
+++ b/README.md
@@ -52,6 +52,7 @@ Light container updating DNS A and/or AAAA records periodically for multiple DNS
- Gandi
- GCP
- GoDaddy
+ - GoIP.de
- He.net
- Hetzner
- Infomaniak
@@ -189,6 +190,7 @@ Check the documentation for your DNS provider:
- [Gandi](docs/gandi.md)
- [GCP](docs/gcp.md)
- [GoDaddy](docs/godaddy.md)
+- [GoIP.de](docs/goip.md)
- [He.net](docs/he.net.md)
- [Infomaniak](docs/infomaniak.md)
- [INWX](docs/inwx.md)
diff --git a/docs/goip.md b/docs/goip.md
new file mode 100644
index 000000000..adc68fd6a
--- /dev/null
+++ b/docs/goip.md
@@ -0,0 +1,35 @@
+# GoIP.de
+
+## Configuration
+
+### Example
+
+```json
+{
+ "settings": [
+ {
+ "provider": "goip.de",
+ "domain": "subdomain",
+ "username": "username",
+ "password": "password",
+ "provider_ip": true,
+ "ip_version": "ipv4",
+ "ipv6_suffix": ""
+ }
+ ]
+}
+```
+
+### Compulsory parameters
+
+- `"domain"`
+- `"username"` is your goip.de username listed un "Routers"
+- `"password"` is your router username password
+
+### Optional parameters
+
+- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
+- `"ipv6_suffix"` is the IPv6 interface identifiersuffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
+- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
+
+## Domain setup
diff --git a/internal/provider/constants/providers.go b/internal/provider/constants/providers.go
index f7ceb913f..646f08f4c 100644
--- a/internal/provider/constants/providers.go
+++ b/internal/provider/constants/providers.go
@@ -25,6 +25,7 @@ const (
Gandi models.Provider = "gandi"
GCP models.Provider = "gcp"
GoDaddy models.Provider = "godaddy"
+ GoIP models.Provider = "goip"
HE models.Provider = "he"
Hetzner models.Provider = "hetzner"
Infomaniak models.Provider = "infomaniak"
@@ -71,6 +72,7 @@ func ProviderChoices() []models.Provider {
Gandi,
GCP,
GoDaddy,
+ GoIP,
HE,
Hetzner,
Infomaniak,
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index cd01912de..6a03c1770 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -31,6 +31,7 @@ import (
"github.com/qdm12/ddns-updater/internal/provider/providers/gandi"
"github.com/qdm12/ddns-updater/internal/provider/providers/gcp"
"github.com/qdm12/ddns-updater/internal/provider/providers/godaddy"
+ "github.com/qdm12/ddns-updater/internal/provider/providers/goip"
"github.com/qdm12/ddns-updater/internal/provider/providers/he"
"github.com/qdm12/ddns-updater/internal/provider/providers/hetzner"
"github.com/qdm12/ddns-updater/internal/provider/providers/infomaniak"
@@ -116,6 +117,8 @@ func New(providerName models.Provider, data json.RawMessage, domain, host string
return gcp.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.GoDaddy:
return godaddy.New(data, domain, host, ipVersion, ipv6Suffix)
+ case constants.GoIP:
+ return goip.New(data, domain, ipVersion, ipv6Suffix)
case constants.HE:
return he.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Hetzner:
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
new file mode 100644
index 000000000..b007500f8
--- /dev/null
+++ b/internal/provider/providers/goip/provider.go
@@ -0,0 +1,169 @@
+package goip
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/netip"
+ "net/url"
+ "strings"
+
+ "github.com/qdm12/ddns-updater/internal/models"
+ "github.com/qdm12/ddns-updater/internal/provider/constants"
+ "github.com/qdm12/ddns-updater/internal/provider/errors"
+ "github.com/qdm12/ddns-updater/internal/provider/headers"
+ "github.com/qdm12/ddns-updater/internal/provider/utils"
+ "github.com/qdm12/ddns-updater/pkg/publicip/ipversion"
+)
+
+type Provider struct {
+ domain string
+ ipVersion ipversion.IPVersion
+ ipv6Suffix netip.Prefix
+ username string
+ password string
+ useProviderIP bool
+}
+
+func New(data json.RawMessage, domain string,
+ ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
+ p *Provider, err error) {
+ extraSettings := struct {
+ Username string `json:"username"`
+ Password string `json:"password"`
+ UseProviderIP bool `json:"providor_ip"`
+ }{}
+ err = json.Unmarshal(data, &extraSettings)
+ if err != nil {
+ return nil, err
+ }
+ p = &Provider{
+ domain: domain,
+ ipVersion: ipVersion,
+ ipv6Suffix: ipv6Suffix,
+ username: extraSettings.Username,
+ password: extraSettings.Password,
+ useProviderIP: extraSettings.UseProviderIP,
+ }
+ err = p.isValid()
+ if err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+func (p *Provider) isValid() error {
+ switch {
+ case p.username == "":
+ return fmt.Errorf("%w", errors.ErrUsernameNotSet)
+ case p.password == "":
+ return fmt.Errorf("%w", errors.ErrPasswordNotSet)
+ }
+ return nil
+}
+
+func (p *Provider) String() string {
+ return utils.ToString(p.domain,"@", constants.GoIP, p.ipVersion)
+}
+
+func (p *Provider) Domain() string {
+ return p.domain
+}
+
+func (p *Provider) Host() string {
+ return "@"
+}
+
+func (p *Provider) IPVersion() ipversion.IPVersion {
+ return p.ipVersion
+}
+
+func (p *Provider) IPv6Suffix() netip.Prefix {
+ return p.ipv6Suffix
+}
+
+func (p *Provider) Proxied() bool {
+ return false
+}
+
+func (p *Provider) BuildDomainName() string {
+ return p.domain
+}
+
+func (p *Provider) HTML() models.HTMLRow {
+ return models.HTMLRow{
+ Domain: fmt.Sprintf("%s", p.BuildDomainName(), p.BuildDomainName()),
+ Host: p.Host(),
+ Provider: "GoIP.de",
+ IPVersion: p.ipVersion.String(),
+ }
+}
+//https://www.goip.de/setip?username=%5BUser%5D&password=%5BPass%5D&subdomain=%5Bsubdomain.goip.de%5D
+func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Addr) (newIP netip.Addr, err error) {
+ u := url.URL{
+ Scheme: "https",
+ User: url.UserPassword(p.username, p.password),
+ Host: "www.goip.de",
+ Path: "/setip",
+ }
+ values := url.Values{}
+ values.Set("subdomain", p.domain)
+ values.Set("username", p.username)
+ values.Set("password", p.password)
+ values.Set("shortResponse", "true")
+ useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
+ if !useProviderIP {
+ values.Set("ip", ip.String())
+ }
+ u.RawQuery = values.Encode()
+
+ request, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
+ fmt.Println(request)
+ if err != nil {
+ return netip.Addr{}, fmt.Errorf("creating http request: %w", err)
+ }
+ headers.SetUserAgent(request)
+
+ response, err := client.Do(request)
+ if err != nil {
+ return netip.Addr{}, fmt.Errorf("doing http request: %w", err)
+ }
+ defer response.Body.Close()
+
+ switch response.StatusCode {
+ case http.StatusOK:
+ case http.StatusNoContent:
+ return ip, nil
+ case http.StatusUnauthorized:
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrAuth)
+ case http.StatusConflict:
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrZoneNotFound)
+ case http.StatusGone:
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrAccountInactive)
+ case http.StatusLengthRequired:
+ return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrIPSentMalformed, ip)
+ case http.StatusPreconditionFailed:
+ return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrPrivateIPSent, ip)
+ case http.StatusServiceUnavailable:
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrDNSServerSide)
+ default:
+ return netip.Addr{}, fmt.Errorf("%w: %d: %s",
+ errors.ErrHTTPStatusNotValid, response.StatusCode, utils.BodyToSingleLine(response.Body))
+ }
+
+ b, err := io.ReadAll(response.Body)
+ if err != nil {
+ return netip.Addr{}, fmt.Errorf("reading response body: %w", err)
+ }
+ s := string(b)
+ fmt.Println("Start:" + s + ":End")
+ switch {
+ case strings.HasPrefix(s, p.domain + " (" + ip.String() + ")"):
+ fmt.Println("All good")
+ return ip, nil
+ default:
+ return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, s)
+ }
+}
From eacc306e94d489abb7691d2e65c84d72cb40ae92 Mon Sep 17 00:00:00 2001
From: CyberAustin
Date: Fri, 2 Feb 2024 19:06:55 +0100
Subject: [PATCH 06/23] Ready to merge, or at least so I think
---
internal/provider/providers/goip/provider.go | 21 ++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index b007500f8..aa739735f 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -65,7 +65,7 @@ func (p *Provider) isValid() error {
}
func (p *Provider) String() string {
- return utils.ToString(p.domain,"@", constants.GoIP, p.ipVersion)
+ return utils.ToString(p.domain, "@", constants.GoIP, p.ipVersion)
}
func (p *Provider) Domain() string {
@@ -100,7 +100,7 @@ func (p *Provider) HTML() models.HTMLRow {
IPVersion: p.ipVersion.String(),
}
}
-//https://www.goip.de/setip?username=%5BUser%5D&password=%5BPass%5D&subdomain=%5Bsubdomain.goip.de%5D
+
func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Addr) (newIP netip.Addr, err error) {
u := url.URL{
Scheme: "https",
@@ -110,9 +110,9 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("subdomain", p.domain)
- values.Set("username", p.username)
- values.Set("password", p.password)
- values.Set("shortResponse", "true")
+ values.Set("username", p.username)
+ values.Set("password", p.password)
+ values.Set("shortResponse", "true")
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
values.Set("ip", ip.String())
@@ -120,7 +120,6 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
u.RawQuery = values.Encode()
request, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
- fmt.Println(request)
if err != nil {
return netip.Addr{}, fmt.Errorf("creating http request: %w", err)
}
@@ -158,11 +157,13 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
return netip.Addr{}, fmt.Errorf("reading response body: %w", err)
}
s := string(b)
- fmt.Println("Start:" + s + ":End")
switch {
- case strings.HasPrefix(s, p.domain + " (" + ip.String() + ")"):
- fmt.Println("All good")
- return ip, nil
+ case strings.HasPrefix(s, p.domain+" ("+ip.String()+")"):
+ return ip, nil
+ case strings.HasPrefix(s, "Zugriff verweigert"):
+ return netip.Addr{}, fmt.Errorf("Username, Password or Subdomain incorrect")
+ case strings.HasPrefix(s, "Die Datenübertragung war fehlerhaft"):
+ return netip.Addr{}, fmt.Errorf(("IP address incorrectly formatted"))
default:
return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, s)
}
From e627729092fde9fe77f8cee35b62332eda556960 Mon Sep 17 00:00:00 2001
From: CyberAustin
Date: Fri, 2 Feb 2024 21:18:45 +0100
Subject: [PATCH 07/23] Fixed or adjusted most comments. Ready for another
review.
---
docs/goip.md | 16 ++++--------
internal/provider/constants/providers.go | 4 +--
internal/provider/provider.go | 6 ++---
internal/provider/providers/goip/provider.go | 26 +++++++++-----------
4 files changed, 21 insertions(+), 31 deletions(-)
diff --git a/docs/goip.md b/docs/goip.md
index adc68fd6a..aa66dc7d1 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -9,12 +9,10 @@
"settings": [
{
"provider": "goip.de",
- "domain": "subdomain",
+ "subdomain": "subdomain",
"username": "username",
"password": "password",
"provider_ip": true,
- "ip_version": "ipv4",
- "ipv6_suffix": ""
}
]
}
@@ -22,14 +20,10 @@
### Compulsory parameters
-- `"domain"`
-- `"username"` is your goip.de username listed un "Routers"
-- `"password"` is your router username password
+- `"subdomain"`
+- `"username"` is your goip.de username listed under "Routers"
+- `"password"` is your router account password
### Optional parameters
-- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
-- `"ipv6_suffix"` is the IPv6 interface identifiersuffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
-- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
-
-## Domain setup
+- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
\ No newline at end of file
diff --git a/internal/provider/constants/providers.go b/internal/provider/constants/providers.go
index 646f08f4c..38e0d0db1 100644
--- a/internal/provider/constants/providers.go
+++ b/internal/provider/constants/providers.go
@@ -25,7 +25,7 @@ const (
Gandi models.Provider = "gandi"
GCP models.Provider = "gcp"
GoDaddy models.Provider = "godaddy"
- GoIP models.Provider = "goip"
+ GoIP models.Provider = "goip"
HE models.Provider = "he"
Hetzner models.Provider = "hetzner"
Infomaniak models.Provider = "infomaniak"
@@ -72,7 +72,7 @@ func ProviderChoices() []models.Provider {
Gandi,
GCP,
GoDaddy,
- GoIP,
+ GoIP,
HE,
Hetzner,
Infomaniak,
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 6a03c1770..d0bc06971 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -31,7 +31,7 @@ import (
"github.com/qdm12/ddns-updater/internal/provider/providers/gandi"
"github.com/qdm12/ddns-updater/internal/provider/providers/gcp"
"github.com/qdm12/ddns-updater/internal/provider/providers/godaddy"
- "github.com/qdm12/ddns-updater/internal/provider/providers/goip"
+ "github.com/qdm12/ddns-updater/internal/provider/providers/goip"
"github.com/qdm12/ddns-updater/internal/provider/providers/he"
"github.com/qdm12/ddns-updater/internal/provider/providers/hetzner"
"github.com/qdm12/ddns-updater/internal/provider/providers/infomaniak"
@@ -117,8 +117,8 @@ func New(providerName models.Provider, data json.RawMessage, domain, host string
return gcp.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.GoDaddy:
return godaddy.New(data, domain, host, ipVersion, ipv6Suffix)
- case constants.GoIP:
- return goip.New(data, domain, ipVersion, ipv6Suffix)
+ case constants.GoIP:
+ return goip.New(data, domain, ipVersion, ipv6Suffix)
case constants.HE:
return he.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Hetzner:
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index aa739735f..f96789900 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -19,7 +19,7 @@ import (
)
type Provider struct {
- domain string
+ subdomain string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
@@ -27,7 +27,7 @@ type Provider struct {
useProviderIP bool
}
-func New(data json.RawMessage, domain string,
+func New(data json.RawMessage, subdomain string,
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
@@ -40,7 +40,7 @@ func New(data json.RawMessage, domain string,
return nil, err
}
p = &Provider{
- domain: domain,
+ subdomain: subdomain,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
@@ -64,14 +64,16 @@ func (p *Provider) isValid() error {
return nil
}
+// "@" necessary to prevent ToString from appending a "." to the FQDN
func (p *Provider) String() string {
- return utils.ToString(p.domain, "@", constants.GoIP, p.ipVersion)
+ return utils.ToString(p.subdomain, "@", constants.GoIP, p.ipVersion)
}
func (p *Provider) Domain() string {
- return p.domain
+ return p.subdomain
}
+// "@" hard coded for compatibility with other provider implementations
func (p *Provider) Host() string {
return "@"
}
@@ -89,7 +91,7 @@ func (p *Provider) Proxied() bool {
}
func (p *Provider) BuildDomainName() string {
- return p.domain
+ return p.subdomain
}
func (p *Provider) HTML() models.HTMLRow {
@@ -109,7 +111,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
Path: "/setip",
}
values := url.Values{}
- values.Set("subdomain", p.domain)
+ values.Set("subdomain", p.subdomain)
values.Set("username", p.username)
values.Set("password", p.password)
values.Set("shortResponse", "true")
@@ -133,8 +135,6 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
switch response.StatusCode {
case http.StatusOK:
- case http.StatusNoContent:
- return ip, nil
case http.StatusUnauthorized:
return netip.Addr{}, fmt.Errorf("%w", errors.ErrAuth)
case http.StatusConflict:
@@ -143,8 +143,6 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
return netip.Addr{}, fmt.Errorf("%w", errors.ErrAccountInactive)
case http.StatusLengthRequired:
return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrIPSentMalformed, ip)
- case http.StatusPreconditionFailed:
- return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrPrivateIPSent, ip)
case http.StatusServiceUnavailable:
return netip.Addr{}, fmt.Errorf("%w", errors.ErrDNSServerSide)
default:
@@ -158,12 +156,10 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
s := string(b)
switch {
- case strings.HasPrefix(s, p.domain+" ("+ip.String()+")"):
+ case strings.HasPrefix(s, p.subdomain+" ("+ip.String()+")"):
return ip, nil
- case strings.HasPrefix(s, "Zugriff verweigert"):
+ case strings.HasPrefix(strings.ToLower(s), "zugriff verweigert"):
return netip.Addr{}, fmt.Errorf("Username, Password or Subdomain incorrect")
- case strings.HasPrefix(s, "Die Datenübertragung war fehlerhaft"):
- return netip.Addr{}, fmt.Errorf(("IP address incorrectly formatted"))
default:
return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, s)
}
From 2b32f01f6204b5b802b8bb5e984784b6c6772476 Mon Sep 17 00:00:00 2001
From: CyberAustin
Date: Fri, 2 Feb 2024 21:37:47 +0100
Subject: [PATCH 08/23] Fixed some linting errors and changed subdomain to FQDN
to make more sense
---
docs/goip.md | 4 ++--
internal/provider/errors/validation.go | 1 +
internal/provider/providers/goip/provider.go | 22 ++++++++++----------
3 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/docs/goip.md b/docs/goip.md
index aa66dc7d1..6c181d0c2 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -9,7 +9,7 @@
"settings": [
{
"provider": "goip.de",
- "subdomain": "subdomain",
+ "fqdn": "mysubdomain.goip.de",
"username": "username",
"password": "password",
"provider_ip": true,
@@ -20,7 +20,7 @@
### Compulsory parameters
-- `"subdomain"`
+- `"subdomain"` is the full FQDN of your ddns address. sample.goip.de or something.goip.it
- `"username"` is your goip.de username listed under "Routers"
- `"password"` is your router account password
diff --git a/internal/provider/errors/validation.go b/internal/provider/errors/validation.go
index c98bc2b5f..6721e9d6a 100644
--- a/internal/provider/errors/validation.go
+++ b/internal/provider/errors/validation.go
@@ -23,6 +23,7 @@ var (
ErrNameNotSet = errors.New("name is not set")
ErrPasswordNotSet = errors.New("password is not set")
ErrPasswordNotValid = errors.New("password is not valid")
+ ErrParametersNotValid = errors.New("Username, Password or FQDN incorrect")
ErrSecretNotSet = errors.New("secret is not set")
ErrSuccessRegexNotSet = errors.New("success regex is not set")
ErrTokenNotSet = errors.New("token is not set")
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index f96789900..4393e36ee 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -19,7 +19,7 @@ import (
)
type Provider struct {
- subdomain string
+ fqdn string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
@@ -27,7 +27,7 @@ type Provider struct {
useProviderIP bool
}
-func New(data json.RawMessage, subdomain string,
+func New(data json.RawMessage, fqdn string,
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
@@ -40,7 +40,7 @@ func New(data json.RawMessage, subdomain string,
return nil, err
}
p = &Provider{
- subdomain: subdomain,
+ fqdn: fqdn,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
@@ -64,16 +64,16 @@ func (p *Provider) isValid() error {
return nil
}
-// "@" necessary to prevent ToString from appending a "." to the FQDN
+// "@" necessary to prevent ToString from appending a "." to the FQDN.
func (p *Provider) String() string {
- return utils.ToString(p.subdomain, "@", constants.GoIP, p.ipVersion)
+ return utils.ToString(p.fqdn, "@", constants.GoIP, p.ipVersion)
}
func (p *Provider) Domain() string {
- return p.subdomain
+ return p.fqdn
}
-// "@" hard coded for compatibility with other provider implementations
+// "@" hard coded for compatibility with other provider implementations.
func (p *Provider) Host() string {
return "@"
}
@@ -91,7 +91,7 @@ func (p *Provider) Proxied() bool {
}
func (p *Provider) BuildDomainName() string {
- return p.subdomain
+ return p.fqdn
}
func (p *Provider) HTML() models.HTMLRow {
@@ -111,7 +111,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
Path: "/setip",
}
values := url.Values{}
- values.Set("subdomain", p.subdomain)
+ values.Set("fqdn", p.fqdn)
values.Set("username", p.username)
values.Set("password", p.password)
values.Set("shortResponse", "true")
@@ -156,10 +156,10 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
s := string(b)
switch {
- case strings.HasPrefix(s, p.subdomain+" ("+ip.String()+")"):
+ case strings.HasPrefix(s, p.fqdn+" ("+ip.String()+")"):
return ip, nil
case strings.HasPrefix(strings.ToLower(s), "zugriff verweigert"):
- return netip.Addr{}, fmt.Errorf("Username, Password or Subdomain incorrect")
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrParametersNotValid)
default:
return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, s)
}
From f6937403a94532612872cabb7640daaee0c0c550 Mon Sep 17 00:00:00 2001
From: CyberAustin <88937794+CyberAustin@users.noreply.github.com>
Date: Fri, 2 Feb 2024 21:42:46 +0100
Subject: [PATCH 09/23] Update goip.md
Added a new line at the end, to make the markdown checker happy.
---
docs/goip.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/goip.md b/docs/goip.md
index 6c181d0c2..afa51ef85 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -26,4 +26,5 @@
### Optional parameters
-- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
\ No newline at end of file
+- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
+-
From 6a33a96f5627827786087f0d9bec2a61af52ab9f Mon Sep 17 00:00:00 2001
From: CyberAustin <88937794+CyberAustin@users.noreply.github.com>
Date: Fri, 2 Feb 2024 21:44:30 +0100
Subject: [PATCH 10/23] Update goip.md
.........and a trailing space
---
docs/goip.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/goip.md b/docs/goip.md
index afa51ef85..84999744f 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -28,3 +28,4 @@
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
-
+
From 639c713ebf2adb8ede0ad28eba2de26c14c07ef6 Mon Sep 17 00:00:00 2001
From: CyberAustin <88937794+CyberAustin@users.noreply.github.com>
Date: Fri, 2 Feb 2024 21:46:33 +0100
Subject: [PATCH 11/23] Update goip.md
Please markdown linter, have mercy
---
docs/goip.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/docs/goip.md b/docs/goip.md
index 84999744f..3eb8a5af9 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -27,5 +27,3 @@
### Optional parameters
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
--
-
From 34b38d6556ab9e799225ac7f65eca20c59bda8b3 Mon Sep 17 00:00:00 2001
From: CyberAustin <88937794+CyberAustin@users.noreply.github.com>
Date: Fri, 2 Feb 2024 22:15:21 +0100
Subject: [PATCH 12/23] Update goip.md
mixed a "subdomain"
---
docs/goip.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/goip.md b/docs/goip.md
index 3eb8a5af9..490fe1d60 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -20,7 +20,7 @@
### Compulsory parameters
-- `"subdomain"` is the full FQDN of your ddns address. sample.goip.de or something.goip.it
+- `"fqdn"` is the full FQDN of your ddns address. sample.goip.de or something.goip.it
- `"username"` is your goip.de username listed under "Routers"
- `"password"` is your router account password
From 7f9ee8db8292899861b4fce07e73cb5b2ce8928c Mon Sep 17 00:00:00 2001
From: CyberAustin
Date: Sat, 3 Feb 2024 14:04:04 +0100
Subject: [PATCH 13/23] Made more changes, per the PR.
---
docs/goip.md | 10 ++++++---
internal/provider/errors/validation.go | 2 +-
internal/provider/provider.go | 2 +-
internal/provider/providers/goip/provider.go | 23 +++++++++++---------
4 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/docs/goip.md b/docs/goip.md
index 6c181d0c2..7139b7c27 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -9,10 +9,12 @@
"settings": [
{
"provider": "goip.de",
- "fqdn": "mysubdomain.goip.de",
+ "host": "mysubdomain.goip.de",
"username": "username",
"password": "password",
"provider_ip": true,
+ "ip_version": "",
+ "ipv6_suffix": ""
}
]
}
@@ -20,10 +22,12 @@
### Compulsory parameters
-- `"subdomain"` is the full FQDN of your ddns address. sample.goip.de or something.goip.it
+- `"host"` is the full FQDN of your ddns address. sample.goip.de or something.goip.it
- `"username"` is your goip.de username listed under "Routers"
- `"password"` is your router account password
### Optional parameters
-- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
\ No newline at end of file
+- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
+- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4`.
+- `"ipv6_suffix"` is the IPv6 interface identifiersuffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
\ No newline at end of file
diff --git a/internal/provider/errors/validation.go b/internal/provider/errors/validation.go
index 6721e9d6a..03ba3df70 100644
--- a/internal/provider/errors/validation.go
+++ b/internal/provider/errors/validation.go
@@ -23,7 +23,7 @@ var (
ErrNameNotSet = errors.New("name is not set")
ErrPasswordNotSet = errors.New("password is not set")
ErrPasswordNotValid = errors.New("password is not valid")
- ErrParametersNotValid = errors.New("Username, Password or FQDN incorrect")
+ ErrParametersNotValid = errors.New("username, password or host incorrect")
ErrSecretNotSet = errors.New("secret is not set")
ErrSuccessRegexNotSet = errors.New("success regex is not set")
ErrTokenNotSet = errors.New("token is not set")
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index d0bc06971..a3e5e76c4 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -118,7 +118,7 @@ func New(providerName models.Provider, data json.RawMessage, domain, host string
case constants.GoDaddy:
return godaddy.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.GoIP:
- return goip.New(data, domain, ipVersion, ipv6Suffix)
+ return goip.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.HE:
return he.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Hetzner:
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index 4393e36ee..1729d825d 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -19,7 +19,7 @@ import (
)
type Provider struct {
- fqdn string
+ host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
@@ -27,7 +27,7 @@ type Provider struct {
useProviderIP bool
}
-func New(data json.RawMessage, fqdn string,
+func New(data json.RawMessage, domain string, host string,
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
@@ -40,7 +40,7 @@ func New(data json.RawMessage, fqdn string,
return nil, err
}
p = &Provider{
- fqdn: fqdn,
+ host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
@@ -60,17 +60,20 @@ func (p *Provider) isValid() error {
return fmt.Errorf("%w", errors.ErrUsernameNotSet)
case p.password == "":
return fmt.Errorf("%w", errors.ErrPasswordNotSet)
+ case !(strings.HasSuffix(p.host, ".goip.de") || strings.HasSuffix(p.host, ".goip.it")):
+ fmt.Println(strings.HasSuffix(p.host, ".goip.de"))
+ return fmt.Errorf("%w", errors.ErrURLNotSet)
}
return nil
}
-// "@" necessary to prevent ToString from appending a "." to the FQDN.
+// "@" necessary to prevent ToString from appending a "." to the host.
func (p *Provider) String() string {
- return utils.ToString(p.fqdn, "@", constants.GoIP, p.ipVersion)
+ return utils.ToString(p.host, "@", constants.GoIP, p.ipVersion)
}
func (p *Provider) Domain() string {
- return p.fqdn
+ return "goip.de"
}
// "@" hard coded for compatibility with other provider implementations.
@@ -91,7 +94,7 @@ func (p *Provider) Proxied() bool {
}
func (p *Provider) BuildDomainName() string {
- return p.fqdn
+ return p.host
}
func (p *Provider) HTML() models.HTMLRow {
@@ -111,7 +114,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
Path: "/setip",
}
values := url.Values{}
- values.Set("fqdn", p.fqdn)
+ values.Set("host", p.host)
values.Set("username", p.username)
values.Set("password", p.password)
values.Set("shortResponse", "true")
@@ -156,11 +159,11 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
s := string(b)
switch {
- case strings.HasPrefix(s, p.fqdn+" ("+ip.String()+")"):
+ case strings.HasPrefix(s, p.host+" ("+ip.String()+")"):
return ip, nil
case strings.HasPrefix(strings.ToLower(s), "zugriff verweigert"):
return netip.Addr{}, fmt.Errorf("%w", errors.ErrParametersNotValid)
default:
- return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, s)
+ return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, utils.ToSingleLine(s))
}
}
From 34eca3cbdbf7ae017d0f82d0782306f4d5281b59 Mon Sep 17 00:00:00 2001
From: CyberAustin
Date: Sat, 3 Feb 2024 14:14:25 +0100
Subject: [PATCH 14/23] Fixed Markdown, maybe
---
docs/goip.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/docs/goip.md b/docs/goip.md
index 0075c9a72..a13270928 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -20,7 +20,7 @@
]
}
```
-
+
### Compulsory parameters
- `"host"` is the full FQDN of your ddns address. sample.goip.de or something.goip.it
@@ -32,4 +32,3 @@
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4`.
- `"ipv6_suffix"` is the IPv6 interface identifiersuffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
-
From 1ea60070c371bb4f9c69d58ba7a4b1673f2ad4d8 Mon Sep 17 00:00:00 2001
From: CyberAustin
Date: Sat, 3 Feb 2024 14:28:20 +0100
Subject: [PATCH 15/23] More lint
---
internal/provider/provider.go | 2 +-
internal/provider/providers/goip/provider.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index a3e5e76c4..5c09adbab 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -118,7 +118,7 @@ func New(providerName models.Provider, data json.RawMessage, domain, host string
case constants.GoDaddy:
return godaddy.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.GoIP:
- return goip.New(data, domain, host, ipVersion, ipv6Suffix)
+ return goip.New(data, host, ipVersion, ipv6Suffix)
case constants.HE:
return he.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Hetzner:
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index 1729d825d..453618c4a 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -27,7 +27,7 @@ type Provider struct {
useProviderIP bool
}
-func New(data json.RawMessage, domain string, host string,
+func New(data json.RawMessage, host string,
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
From f06448defe651deb98383132f18590633f26cbb0 Mon Sep 17 00:00:00 2001
From: Quentin McGaw
Date: Sat, 3 Feb 2024 15:11:46 +0000
Subject: [PATCH 16/23] Fix typo providor_ip -> provider_ip
---
internal/provider/providers/goip/provider.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index 453618c4a..6764f783e 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -33,7 +33,7 @@ func New(data json.RawMessage, host string,
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
- UseProviderIP bool `json:"providor_ip"`
+ UseProviderIP bool `json:"provider_ip"`
}{}
err = json.Unmarshal(data, &extraSettings)
if err != nil {
From 8638bb8fda7c8cf7c9b11d3e85741308a9aef4d4 Mon Sep 17 00:00:00 2001
From: Quentin McGaw
Date: Sat, 3 Feb 2024 17:26:34 +0000
Subject: [PATCH 17/23] Use host as intended
---
docs/goip.md | 4 ++-
internal/provider/errors/validation.go | 1 +
internal/provider/provider.go | 2 +-
internal/provider/providers/goip/provider.go | 34 ++++++++++++--------
4 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/docs/goip.md b/docs/goip.md
index a13270928..6be1a1be4 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -9,7 +9,8 @@
"settings": [
{
"provider": "goip.de",
- "host": "mysubdomain.goip.de",
+ "domain": "goip.de",
+ "host": "mysubdomain",
"username": "username",
"password": "password",
"provider_ip": true,
@@ -29,6 +30,7 @@
### Optional parameters
+- `"domain"` is the domain name which can be `goip.de` or `goip.it`, and defaults to `goip.de` if left unset.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4`.
- `"ipv6_suffix"` is the IPv6 interface identifiersuffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
diff --git a/internal/provider/errors/validation.go b/internal/provider/errors/validation.go
index 03ba3df70..586a78928 100644
--- a/internal/provider/errors/validation.go
+++ b/internal/provider/errors/validation.go
@@ -14,6 +14,7 @@ var (
ErrEmailNotSet = errors.New("email is not set")
ErrEmailNotValid = errors.New("email address is not valid")
ErrGCPProjectNotSet = errors.New("GCP project is not set")
+ ErrDomainNotValid = errors.New("domain is not valid")
ErrHostOnlySubdomain = errors.New("host can only be a subdomain")
ErrHostWildcard = errors.New(`host cannot be a "*"`)
ErrIPv4KeyNotSet = errors.New("IPv4 key is not set")
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 5c09adbab..a3e5e76c4 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -118,7 +118,7 @@ func New(providerName models.Provider, data json.RawMessage, domain, host string
case constants.GoDaddy:
return godaddy.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.GoIP:
- return goip.New(data, host, ipVersion, ipv6Suffix)
+ return goip.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.HE:
return he.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Hetzner:
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index 6764f783e..c70633ceb 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -19,6 +19,7 @@ import (
)
type Provider struct {
+ domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
@@ -27,9 +28,15 @@ type Provider struct {
useProviderIP bool
}
-func New(data json.RawMessage, host string,
+const defaultDomain = "goip.de"
+
+func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
+ if domain == "" {
+ domain = defaultDomain
+ }
+
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -40,6 +47,7 @@ func New(data json.RawMessage, host string,
return nil, err
}
p = &Provider{
+ domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
@@ -60,25 +68,25 @@ func (p *Provider) isValid() error {
return fmt.Errorf("%w", errors.ErrUsernameNotSet)
case p.password == "":
return fmt.Errorf("%w", errors.ErrPasswordNotSet)
- case !(strings.HasSuffix(p.host, ".goip.de") || strings.HasSuffix(p.host, ".goip.it")):
- fmt.Println(strings.HasSuffix(p.host, ".goip.de"))
- return fmt.Errorf("%w", errors.ErrURLNotSet)
+ case p.domain != defaultDomain && p.domain != "goip.it":
+ return fmt.Errorf(`%w: %q must be "goip.de" or "goip.it"`,
+ errors.ErrDomainNotValid, p.domain)
+ case p.host == "@" || p.host == "*":
+ return fmt.Errorf("%w: host %q is not valid", errors.ErrHostOnlySubdomain, p.host)
}
return nil
}
-// "@" necessary to prevent ToString from appending a "." to the host.
func (p *Provider) String() string {
- return utils.ToString(p.host, "@", constants.GoIP, p.ipVersion)
+ return utils.ToString(p.host, p.domain, constants.GoIP, p.ipVersion)
}
func (p *Provider) Domain() string {
- return "goip.de"
+ return p.domain
}
-// "@" hard coded for compatibility with other provider implementations.
func (p *Provider) Host() string {
- return "@"
+ return p.host
}
func (p *Provider) IPVersion() ipversion.IPVersion {
@@ -94,14 +102,14 @@ func (p *Provider) Proxied() bool {
}
func (p *Provider) BuildDomainName() string {
- return p.host
+ return utils.BuildDomainName(p.host, p.domain)
}
func (p *Provider) HTML() models.HTMLRow {
return models.HTMLRow{
Domain: fmt.Sprintf("%s", p.BuildDomainName(), p.BuildDomainName()),
Host: p.Host(),
- Provider: "GoIP.de",
+ Provider: "" + p.domain + "",
IPVersion: p.ipVersion.String(),
}
}
@@ -114,7 +122,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
Path: "/setip",
}
values := url.Values{}
- values.Set("host", p.host)
+ values.Set("host", p.BuildDomainName())
values.Set("username", p.username)
values.Set("password", p.password)
values.Set("shortResponse", "true")
@@ -159,7 +167,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
s := string(b)
switch {
- case strings.HasPrefix(s, p.host+" ("+ip.String()+")"):
+ case strings.HasPrefix(s, p.BuildDomainName()+" ("+ip.String()+")"):
return ip, nil
case strings.HasPrefix(strings.ToLower(s), "zugriff verweigert"):
return netip.Addr{}, fmt.Errorf("%w", errors.ErrParametersNotValid)
From 4ae33af9146f9c7240ac1843abba985d700f123d Mon Sep 17 00:00:00 2001
From: Quentin McGaw
Date: Sat, 3 Feb 2024 17:28:26 +0000
Subject: [PATCH 18/23] Use ErrBadRequest instead of ErrParametersNotValid and
add "(access denied)" to error
---
internal/provider/errors/validation.go | 1 -
internal/provider/providers/goip/provider.go | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/internal/provider/errors/validation.go b/internal/provider/errors/validation.go
index 586a78928..bf61a62c8 100644
--- a/internal/provider/errors/validation.go
+++ b/internal/provider/errors/validation.go
@@ -24,7 +24,6 @@ var (
ErrNameNotSet = errors.New("name is not set")
ErrPasswordNotSet = errors.New("password is not set")
ErrPasswordNotValid = errors.New("password is not valid")
- ErrParametersNotValid = errors.New("username, password or host incorrect")
ErrSecretNotSet = errors.New("secret is not set")
ErrSuccessRegexNotSet = errors.New("success regex is not set")
ErrTokenNotSet = errors.New("token is not set")
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index c70633ceb..8d98b371c 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -170,7 +170,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
case strings.HasPrefix(s, p.BuildDomainName()+" ("+ip.String()+")"):
return ip, nil
case strings.HasPrefix(strings.ToLower(s), "zugriff verweigert"):
- return netip.Addr{}, fmt.Errorf("%w", errors.ErrParametersNotValid)
+ return netip.Addr{}, fmt.Errorf("%w (access denied)", errors.ErrBadRequest)
default:
return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, utils.ToSingleLine(s))
}
From d0bed8d9fffaf90b5a6c16caf6193020658b711d Mon Sep 17 00:00:00 2001
From: Quentin McGaw
Date: Sat, 3 Feb 2024 17:32:42 +0000
Subject: [PATCH 19/23] Handle IPv6 addresses correctly
---
internal/provider/providers/goip/provider.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index 8d98b371c..e6746a1d4 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -128,7 +128,11 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
values.Set("shortResponse", "true")
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
- values.Set("ip", ip.String())
+ if ip.Is4() {
+ values.Set("ip", ip.String())
+ } else {
+ values.Set("ip6", ip.String())
+ }
}
u.RawQuery = values.Encode()
From 77db29e3244e2401cc0256705361489bf3cca761 Mon Sep 17 00:00:00 2001
From: Quentin McGaw
Date: Sat, 3 Feb 2024 17:34:02 +0000
Subject: [PATCH 20/23] Always send IPv6 address query parameter (provider
limitation)
---
docs/goip.md | 2 +-
internal/provider/providers/goip/provider.go | 11 ++++++-----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/docs/goip.md b/docs/goip.md
index 6be1a1be4..0a403ed14 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -31,6 +31,6 @@
### Optional parameters
- `"domain"` is the domain name which can be `goip.de` or `goip.it`, and defaults to `goip.de` if left unset.
-- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
+- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request. This is automatically disabled for an IPv6 public address since it is not supported.
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4`.
- `"ipv6_suffix"` is the IPv6 interface identifiersuffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index e6746a1d4..78f3bb132 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -114,6 +114,7 @@ func (p *Provider) HTML() models.HTMLRow {
}
}
+// See https://www.goip.de/update-url.html
func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Addr) (newIP netip.Addr, err error) {
u := url.URL{
Scheme: "https",
@@ -126,13 +127,13 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
values.Set("username", p.username)
values.Set("password", p.password)
values.Set("shortResponse", "true")
- useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
- if !useProviderIP {
- if ip.Is4() {
+ if ip.Is4() {
+ if !p.useProviderIP {
values.Set("ip", ip.String())
- } else {
- values.Set("ip6", ip.String())
}
+ } else {
+ // IPv6 cannot be automatically detected
+ values.Set("ip6", ip.String())
}
u.RawQuery = values.Encode()
From bafe1a38f53fac9585b450286c9084eca14a234d Mon Sep 17 00:00:00 2001
From: Quentin McGaw
Date: Sat, 3 Feb 2024 17:44:41 +0000
Subject: [PATCH 21/23] Fix provider name in docs/goip.md
---
docs/goip.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/goip.md b/docs/goip.md
index 0a403ed14..9dd7eff12 100644
--- a/docs/goip.md
+++ b/docs/goip.md
@@ -8,7 +8,7 @@
{
"settings": [
{
- "provider": "goip.de",
+ "provider": "goip",
"domain": "goip.de",
"host": "mysubdomain",
"username": "username",
From b5c7a42668628db5220dd65f2d0f4b602854f196 Mon Sep 17 00:00:00 2001
From: Quentin McGaw
Date: Sat, 3 Feb 2024 17:51:51 +0000
Subject: [PATCH 22/23] Review error processing - Remove seemingly copy-pasted
errors from an irrelevant provider - No documentation found on status codes,
so anything else than 200 is considered a fail - Change access denied error
to wrap sentinel ErrAuth
---
internal/provider/providers/goip/provider.go | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index 78f3bb132..01869d376 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -149,21 +149,10 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
defer response.Body.Close()
- switch response.StatusCode {
- case http.StatusOK:
- case http.StatusUnauthorized:
- return netip.Addr{}, fmt.Errorf("%w", errors.ErrAuth)
- case http.StatusConflict:
- return netip.Addr{}, fmt.Errorf("%w", errors.ErrZoneNotFound)
- case http.StatusGone:
- return netip.Addr{}, fmt.Errorf("%w", errors.ErrAccountInactive)
- case http.StatusLengthRequired:
- return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrIPSentMalformed, ip)
- case http.StatusServiceUnavailable:
- return netip.Addr{}, fmt.Errorf("%w", errors.ErrDNSServerSide)
- default:
+ if response.StatusCode != http.StatusOK {
return netip.Addr{}, fmt.Errorf("%w: %d: %s",
- errors.ErrHTTPStatusNotValid, response.StatusCode, utils.BodyToSingleLine(response.Body))
+ errors.ErrHTTPStatusNotValid, response.StatusCode,
+ utils.BodyToSingleLine(response.Body))
}
b, err := io.ReadAll(response.Body)
@@ -175,7 +164,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
case strings.HasPrefix(s, p.BuildDomainName()+" ("+ip.String()+")"):
return ip, nil
case strings.HasPrefix(strings.ToLower(s), "zugriff verweigert"):
- return netip.Addr{}, fmt.Errorf("%w (access denied)", errors.ErrBadRequest)
+ return netip.Addr{}, fmt.Errorf("%w", errors.ErrAuth)
default:
return netip.Addr{}, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, utils.ToSingleLine(s))
}
From 214e52d885b060c203de67c74993f3bd1123a3b6 Mon Sep 17 00:00:00 2001
From: Quentin McGaw
Date: Sat, 3 Feb 2024 17:54:31 +0000
Subject: [PATCH 23/23] Fix subdomain query parameter key
---
internal/provider/providers/goip/provider.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/internal/provider/providers/goip/provider.go b/internal/provider/providers/goip/provider.go
index 01869d376..791a53e88 100644
--- a/internal/provider/providers/goip/provider.go
+++ b/internal/provider/providers/goip/provider.go
@@ -123,7 +123,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
Path: "/setip",
}
values := url.Values{}
- values.Set("host", p.BuildDomainName())
+ values.Set("subdomain", p.BuildDomainName())
values.Set("username", p.username)
values.Set("password", p.password)
values.Set("shortResponse", "true")